OffsetDateTime失败,使用本地化格式化程序使用FormatStyle的LONG或FULL
tl; dr
失败。OffsetDateTime失败,使用本地化格式化程序使用FormatStyle的LONG或FULL
OffsetDateTime.now()
.format(
DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG)
) // throws DateTimeException.
但是在ZonedDateTime
工作中具有相同偏移量的同一时刻。
为什么?
详细
当让java.time
通过DateTimeFormatter.ofLocalizedDateTime
自动本地化OffsetDateTime
的字符串表示,呼吁format
作品,如果格式化携带SHORT
或MEDIUM
一个FormatStyle
。但是,如果格式化程序包含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分十四秒ž
坏。
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
这个转换?
➟OffsetDateTime
格式化失败的行为是一个错误还是一个功能?
我会提交一个错误报告,但我想确保我误解了一些东西。
调试代码,我发现,格式化的this line结束(grepcode的路线是不完全一样的号码我的JDK安装的,但代码):
ZoneId zone = context.getValue(TemporalQueries.zoneId());
它试图提取该区域使用内置查询TemporalQueries.zoneId()
。根据javadoc,该查询返回null
如果时间对象是OffsetDateTime
:
这样一个ZonedDateTime将返回getZone()的结果,而是一个OffsetDateTime将返回null。
您可以致电odt.query(TemporalQueries.zoneId())
确认 - 确实返回null
。
后来,这个查询的结果是checked by a DateTimePrintContext
:
R result = temporal.query(query);
if (result == null && optional == 0) {
throw new DateTimeException("Unable to extract value: " + temporal.getClass());
}
由于result
是null
,它会抛出异常。由于这种模式在上述问题的行结束
// 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
模式,这意味着它会为最失败的(如果不是全部)语言环境。
没有直接关系,但你与ZoneOffset
作为参数调用atZoneSameInstant
,你可以简单地调用odt.toZonedDateTime()
代替。
看起来像是报告的Javadoc错误here。在提供的例子中,他们使用LocalDateTime
,但行为是相同的。
采用FormatStyle.LONG
和FormatStyle.FULL
seems需要一个ZoneId
这OffsetDateTime
没有
请仔细阅读
java.time
javadoc的改进,突出一个共同 误解有关格式化需要一个时区中 除了时间因素。当使用区域设置特定的格式,它可能如果区域 格式不需要时区或如果区域 格式需要一个时区,而不是提供一个时区的工作失败。
这就是为什么they clarified the javadoc提
* 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}.
你能创造的DateTimeFormatter
的OffsetDateTime
的ZoneOffset
。
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG)
.withZone(odt.getOffset());
在这种情况下的格式发生之前OffsetDateTime
将被转换为一个ZonedDateTime
。