2017-09-16 3 views
2

tl; dr

이 작업은 실패합니다.FormatStyle을 LONG 또는 FULL로 사용하여 지역화 된 포맷터에서 OffsetDateTime이 실패합니다.

OffsetDateTime.now() 
       .format( 
        DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG) 
      ) // throws DateTimeException. 

동일한 오프셋을 사용하여 동일한 시간에 ZonedDateTime이 작동합니다.

왜?

세부

포맷터가 SHORT 또는 MEDIUMFormatStyle을 수행하는 경우 format 작품을 호출, java.time 자동 DateTimeFormatter.ofLocalizedDateTime를 통해 OffsetDateTime의 문자열 표현을 현지화시키는. 그러나 포맷터가 LONG 또는 FULL 인 경우 DateTimeException이 발생합니다. 그러나 ZonedDateTime은 동일한 offset과 동일한 순간을 사용하여 성공합니다. 왜?

DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG) ; 

OffsetDateTime odt = OffsetDateTime.now(ZoneId.systemDefault()) ; 
ZonedDateTime zdt = odt.atZoneSameInstant(odt.getOffset()) ; // Generate a `ZonedDateTime` with same moment and same offset as the `OffsetDateTime`. 

// Succeeds. 
String outputZdt = zdt.format(f) ; 
System.out.println("outputZdt: " + outputZdt) ; 

// Fails. Throws exception. 
if (false) { 
String outputOdt = odt.format(f) ; // Throws exception. 
System.out.println("outputOdt: " + outputOdt) ; 
} 

이 부분은 code run live at IdeOne.com입니다.

실행시 ...

좋습니다.

outputZdt : 2017년 9월 16일 오전 8시 42분 14초의 Z

나쁜.

Exception in thread "main" java.time.DateTimeException: Unable to extract value: class java.time.OffsetDateTime 
    at java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:282) 
    at java.time.format.DateTimeFormatterBuilder$ZoneTextPrinterParser.format(DateTimeFormatterBuilder.java:3682) 
    at java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2179) 
    at java.time.format.DateTimeFormatterBuilder$LocalizedPrinterParser.format(DateTimeFormatterBuilder.java:4347) 
    at java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2179) 
    at java.time.format.DateTimeFormatter.formatTo(DateTimeFormatter.java:1746) 
    at java.time.format.DateTimeFormatter.format(DateTimeFormatter.java:1720) 
    at java.time.OffsetDateTime.format(OffsetDateTime.java:1674) 
    at Ideone.main(Main.java:28) 

나는 발생을 제외하고, odt.atZoneSameInstant(odt.getOffset())를 해결하기 위해 해당 코드의 핵심을 썼다. 그런 다음 깨달았습니다. 왜 java.time 내부적으로 같은 일을하지 않습니까? 왜 OffsetDateTime은 같은 순간과 동일한 오프셋을 가진 ZonedDateTime이 성공할 때 포맷하지 못합니까? 이 전환을 OffsetDateTime에서 ZonedDateTime으로 변경해야하는 이유는 무엇입니까?

➟이 동작이 버그 또는 기능에 실패 했습니까?

나는 버그 보고서를 제출 하겠지만, 내가 뭔가를 오해하고 있는지 확인하고 싶다.

ZoneId zone = context.getValue(TemporalQueries.zoneId()); 

그것은 추출을 시도 : 코드를 디버깅

답변

1

, 나는 포맷터 (grepcode의 라인이 정확히 내 JDK 설치의 같은 번호가 아니라 코드가) this line에 끝나는 것으로 나타났습니다 영역에 내장 된 쿼리 TemporalQueries.zoneId()을 사용합니다.

는 따라서 ZonedDateTime가 getZone()의 결과를 반환하지만 OffsetDateTime 널 반환 : javadoc에 따르면, 오브젝트가 시간 OffsetDateTime 경우,이 질의는 null를 반환한다.

odt.query(TemporalQueries.zoneId())을 호출하여이를 확인할 수 있습니다. null을 실제로 반환합니다.

나중에,이 쿼리의 결과는 checked by a DateTimePrintContext 경우 : resultnull입니다

R result = temporal.query(query); 
if (result == null && optional == 0) { 
    throw new DateTimeException("Unable to extract value: " + temporal.getClass()); 
} 

으로, 그것은 예외가 발생합니다. 이 패턴은 위에서 설명한 문제가있는 라인에 끝나기 때문에

// java.time.DateTimeException: Unable to extract value: class java.time.OffsetDateTime 
DateTimeFormatter.ofPattern("z").format(OffsetDateTime.now()); 

:


사실, OffsetDateTime에서 (패턴 z) 영역 이름을 얻으려고하면 예외가 발생합니다. getLocalizedDateTimePattern 사용

그리고 모든 로케일의 날짜 스타일을 확인 :

// did this for all locales 
DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.LONG, FormatStyle.LONG, 
    IsoChronology.INSTANCE, locale); 

내가 모두를 확인하지 못했지만, 그들의 대부분은 대부분 실패한다는 것을 의미 소문자 z 패턴을 가지고 (있는 경우 모두는 아님) 로케일.


직접 관련이 있지만, 매개 변수로 ZoneOffsetatZoneSameInstant를 호출하고, 당신은 단순히 대신 odt.toZonedDateTime()를 호출 할 수 없습니다.

3

Javadoc 버그가 here으로보고 된 것 같습니다. 제공된 예제에서는 LocalDateTime을 사용하지만 동작은 동일합니다.

FormatStyle.LONGFormatStyle.FULLseems의 사용은 ZoneId 어떤 OffsetDateTime

이 시간 이외에 시간대를 필요 요소 서식 지정에 대한 일반적인 오해를 강조 java.time javadoc의 개선을 검토하시기 바랍니다 없습니다 필요합니다 .

로캘 특정 서식을 사용하는 경우 로캘 서식에 시간대가 필요하지 않거나 로캘 서식에 시간대가 필요하고 시간대가 제공되지 않으면 오류가 발생할 수 있습니다.

they clarified the javadoc 당신은 함께 DateTimeFormatter를 만들 수

* The {@code FULL} and {@code LONG} styles typically require a time-zone. 
* When formatting using these styles, a {@code ZoneId} must be available, 
* either by using {@code ZonedDateTime} or {@link DateTimeFormatter#withZone}. 

을 언급하는 이유는 어느 OffsetDateTimeZoneOffset. 서식이 발생하기 전에

DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG) 
            .withZone(odt.getOffset()); 

는이 경우에 OffsetDateTimeZonedDateTime로 변환한다.

관련 문제