Java 8 - DateTimeFormatter 和 ZonedDateTime 的ISO_INSTANT问题

2022-08-31 17:33:58

因此,我希望此代码在新的Java 8日期/时间包下工作,因为它所做的只是使用相同的内置DateTimeTer实例(ISO_INSTANT)将给定的ZonedDateTime转换为字符串并返回:

ZonedDateTime now = ZonedDateTime.now();
System.out.println(ZonedDateTime.parse(
    now.format(DateTimeFormatter.ISO_INSTANT),
    DateTimeFormatter.ISO_INSTANT));

但显然它没有:

Exception in thread "main" java.time.format.DateTimeParseException: Text '2014-09-01T19:37:48.549Z' could not be parsed: Unable to obtain ZonedDateTime from TemporalAccessor: {MilliOfSecond=549, NanoOfSecond=549000000, MicroOfSecond=549000, InstantSeconds=1409600268},ISO of type java.time.format.Parsed
    at java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:1918)
    at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1853)
    at java.time.ZonedDateTime.parse(ZonedDateTime.java:597)

我已经看过这个条目,但它没有帮助我,因为需要一个ZonedDateTime对象而不是本地对象,也因为我已经安装了8u20:无法使用Java 8中的DateTimeFormatter和ZonedDateTime从TemporalAccessor获取ZonedDateTime

有人知道这里发生了什么吗?


答案 1

格式化程序记录在这里 - “这是一个特殊情况的格式化程序,旨在允许即时的人类可读形式”。因此,此格式化程序旨在与 非 .ISO_INSTANTInstantZonedDateTime

格式

设置格式时,可以设置任何可以提供 和 的时态对象的格式。两者都可以提供这两个字段,因此两者都有效:ISO_INSTANTChronoField.INSTANT_SECONDSChronoField.NANO_OF_SECONDInstantZonedDateTime

// works with Instant
Instant instant = Instant.now();
System.out.println(DateTimeFormatter.ISO_INSTANT.format(instant));

// works with ZonedDateTime 
ZonedDateTime zdt = ZonedDateTime.now();
System.out.println(zdt.format(DateTimeFormatter.ISO_INSTANT));

// example output
2014-09-02T08:05:23.653Z

解析

解析时,将仅生成 和 。可以从这两个字段构建 ,但也需要一个:ISO_INSTANTChronoField.INSTANT_SECONDSChronoField.NANO_OF_SECONDInstantZonedDateTimeZoneId

要解析 a,必须存在时区。时区可以 (a) 从字符串解析,或 (b) 指定给格式化程序(使用 JDK 8u20):ZonedDateTimeZoneId

// option a - parsed from the string
DateTimeFormatter f = DateTimeFormatter.ISO_DATE_TIME;
ZonedDateTime zdt = ZonedDateTime.parse("2014-09-02T08:05:23.653Z", f);

// option b - specified in the formatter - REQUIRES JDK 8u20 !!!
DateTimeFormatter f = DateTimeFormatter.ISO_INSTANT.withZone(ZoneId.systemDefault());
ZonedDateTime zdt = ZonedDateTime.parse("2014-09-02T08:05:23.653Z", f);

请参阅文档以了解ISO_ZONED_DATE_TIMEISO_OFFSET_DATE_TIMEISO_DATE_TIME(这三者中的任何一个都可用于解析 ,而无需指定 )。ZonedDateTimewithZone()

总结

格式化程序是一种特殊大小写的格式化程序,旨在与 一起使用。如果使用的是,则应使用其他格式化程序,如 或 。ISO_INSTANTInstantZonedDateTimeISO_DATE_TIMEISO_ZONED_DATE_TIME


答案 2

我不确定,但这可能是Java 8中的一个错误。也许它的目的是以这种方式运行,但我认为我将向您提出的解决方法应该是默认行为(如果未指定ZoneId,只需采用系统默认值):

ZonedDateTime now = ZonedDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT
    .withZone(ZoneId.systemDefault());
System.out
    .println(ZonedDateTime.parse(now.format(formatter), formatter));

在OpenJDK中修复了一个类似的错误:JDK-8033662 - 但它只是相似,并不完全相同。


推荐