为什么我的日期时间解析尝试失败?

dav*_*ave 3 java datetime parsing java-8 java-time

我正在以两种略有不同的格式解析同一个日期,但遇到了一个我不明白的错误。

解析标准ISO格式的字符串成功:

    String s = "2018-04-17T22:57:29";
    LocalDateTime date = LocalDateTime.parse(s, DateTimeFormatter.ISO_DATE_TIME);  // OK
Run Code Online (Sandbox Code Playgroud)

但是,当我添加后缀 a"Z"并使用时ISO_INSTANT

    s = "2018-04-17T22:57:29Z";
    date = LocalDateTime.parse(s, DateTimeFormatter.ISO_INSTANT); // Fails
Run Code Online (Sandbox Code Playgroud)

我收到以下异常:

Exception in thread "main" java.time.format.DateTimeParseException: Text '2018-04-17T22:57:29Z' could not be parsed: Unable to obtain LocalDateTime from TemporalAccessor: {MicroOfSecond=0, NanoOfSecond=0, MilliOfSecond=0, InstantSeconds=1524005849},ISO of type java.time.format.Parsed
at java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:1920)
at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1855)
at java.time.LocalDateTime.parse(LocalDateTime.java:492)
at iplus.fwk.manifest.Test.main(Test.java:37)
Caused by: java.time.DateTimeException: Unable to obtain LocalDateTime from TemporalAccessor: {MicroOfSecond=0, NanoOfSecond=0, MilliOfSecond=0, InstantSeconds=1524005849},ISO of type java.time.format.Parsed
at java.time.LocalDateTime.from(LocalDateTime.java:461)
at java.time.format.Parsed.query(Parsed.java:226)
at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)
... 2 more
Caused by: java.time.DateTimeException: Unable to obtain LocalDate from TemporalAccessor: {MicroOfSecond=0, NanoOfSecond=0, MilliOfSecond=0, InstantSeconds=1524005849},ISO of type java.time.format.Parsed
at java.time.LocalDate.from(LocalDate.java:368)
at java.time.LocalDateTime.from(LocalDateTime.java:456)
... 4 more
Run Code Online (Sandbox Code Playgroud)

我对ISO_INSTANT定义的阅读 表明第二次解析应该成功。我究竟做错了什么?

Ole*_*.V. 6

我相信正确的思考方式是这样的:从概念上讲,瞬间不是日期和时间。只是,一瞬间。它没有时区或偏移量,因此不能有日期和时间。由于一个LocalDateTime需要日期和时间,因此解析为瞬间并不能满足您的需求。

是的,我知道:在执行Instant应用时间,因为时代和时代的迄今为止最常见的定义使用UTC。我也知道,你解析字符串持有日期和时间,并且这两个DateTimeFormatter.ISO_INSTANTInstant.toString产生类似的字符串。不过,这是接口,并没有告诉您瞬间的概念是什么。

我对 ISO_INSTANT 定义的阅读表明第二次解析应该成功。

我知道可以这样阅读定义。不过,我认为这是值得注意的:

……瞬间是从 ChronoField.INSTANT_SECONDS 和 ChronoField.NANO_OF_SECOND 转换而来的……

虽然纳秒与其他日期时间类型(如 )共享LocalDateTime,但提到的两个字段不足以为您提供LocalDateTime. 所以这就是它为你打破的地方。要获得一个,LocalDateTime我们需要假设一个时区或偏移量。即使引用继续:

…使用UTC偏移量。

— 这仅意味着 UTC 偏移量用于计算即时秒和纳秒,而不用于进一步处理。

我们也可能会尝试更仔细地研究您的错误消息:

线程“main”中的异常 java.time.format.DateTimeParseException:无法解析文本“2018-04-17T22:57:29Z”:无法从 TemporalAccessor 获取 LocalDateTime:{MicroOfSecond=0、NanoOfSecond=0、MilliOfSecond=0 , InstantSeconds=1524005849},java.time.format.Parsed 类型的 ISO

这也说明我们从解析中得到的只是瞬间秒数(即自纪元以来的秒数)和几分之一秒(以及 ISO 年表)。并且这还不足以获得LocalDateTime.

您不是第一个(也不是最后一个)感到惊讶的人。不过,您观察到的行为是设计使然。

修复

的定义ISO_INSTANT还提到:

ISO_OFFSET_DATE_TIME...

所以这有效:

    String s = "2018-04-17T22:57:29Z";
    LocalDateTime date = LocalDateTime.parse(s, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
Run Code Online (Sandbox Code Playgroud)

结果是2018-04-17T22:57:29(如预期的那样)。