Java 8 - 使用ZonedDateTime的DateTimeFormatter和ISO_INSTANT问题

asi*_*ira 39 java java-8 java-time

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

ZonedDateTime now = ZonedDateTime.now();
System.out.println(ZonedDateTime.parse(
    now.format(DateTimeFormatter.ISO_INSTANT),
    DateTimeFormatter.ISO_INSTANT));
Run Code Online (Sandbox Code Playgroud)

但显然它没有:

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)
Run Code Online (Sandbox Code Playgroud)

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

任何人都知道这里发生了什么?

Jod*_*hen 60

ISO_INSTANT格式是记录在这里 - "这是一个特殊的情况下格式化旨在允许即时的人类可读的形式".因此,此格式化程序适用于Instant非a ZonedDateTime.

格式化

当格式化,ISO_INSTANT可以格式化任何时间对象,可以提供ChronoField.INSTANT_SECONDSChronoField.NANO_OF_SECOND.双方InstantZonedDateTime能提供这两个领域,因此这两种工作方式:

// 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
Run Code Online (Sandbox Code Playgroud)

解析

解析时,ISO_INSTANT只会产生ChronoField.INSTANT_SECONDSChronoField.NANO_OF_SECOND.一个Instant可以从这两个领域建立,但ZonedDateTime需要ZoneId,以及:

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

// 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);
Run Code Online (Sandbox Code Playgroud)

请参阅以下文档ISO_ZONED_DATE_TIME:ISO_OFFSET_DATE_TIMEISO_DATE_TIME(这三个中的任何一个都可用于解析a ZonedDateTime而不指定withZone()).

摘要

ISO_INSTANT格式是一种特殊情况下格式化设计的工作Instant.如果您使用的是ZonedDateTime,则应使用其他格式化程序,例如ISO_DATE_TIMEISO_ZONED_DATE_TIME.

  • 关于这一点的奇怪之处在于,生成的字符串上的最终Z是UTC的时区指示符,因此该字符串确实包含时区指示符(http://en.wikipedia.org/wiki/ISO_8601#Time_zone_designators).但是,文档确实说明这只适用于瞬间,所以你是绝对正确的.谢谢. (3认同)