多种 ISO 8601 到 ZonedDateTime 解析方法的区别

Difference between multiple ISO 8601 to ZonedDateTime parsing methods

我正在尝试以 UTC 格式验证日期时间并将具有任何偏移量的日期时间存储到数据库中。

为了验证,我使用

DateTimeFormatter.ISO_ZONED_DATE_TIME.parseUnresolved(dateString, new ParsePosition(0));

当以 -25:00 的偏移量调用时,会抛出 java.time.DateTimeException: Value out of range: Hour[0-23], Minute[0-59], Second[0-59]。对于任何其他无效字符串,此 returns null.

但是当我尝试使用

解析它时
ZonedDateTime.parse(dateString)

当使用正确的偏移量 -23:00 时,会抛出 Text '2012-04-23T18:25:43.511-23:00' could not be parsed: Zone offset not in valid range: -18:00 to +18:00。如果我查找方法定义,它似乎使用相同的解析方法 DateTimeFormatter.ISO_ZONED_DATE_TIME

public static ZonedDateTime parse(CharSequence text) {
    return parse(text, DateTimeFormatter.ISO_ZONED_DATE_TIME);
}

我的问题是,为什么解析 ISO 8601 日期时间有不同的偏移量限制?

documentation 在这里描述了这种差异:

Parsing is implemented as a two-phase operation. First, the text is parsed using the layout defined by the formatter, producing a Map of field to value, a ZoneId and a Chronology. Second, the parsed data is resolved, by validating, combining and simplifying the various fields into more useful ones.

Five parsing methods are supplied by this class. Four of these perform both the parse and resolve phases. The fifth method, parseUnresolved(CharSequence, ParsePosition), only performs the first phase, leaving the result unresolved. As such, it is essentially a low-level operation.

所以 parseUnresolved 不做,但 parse 做的事情是“验证 [...] 各个字段”。在这种情况下,parse 检查偏移量是否在 ChronoField.OFFSET_SECONDS.range()(±18 小时)内。 parseUnresolved 不会这样做,就像它不检查第 20 个月是否是有效月份一样:

System.out.println(
    // this returns a non-null value
    DateTimeFormatter.ISO_LOCAL_DATE.parseUnresolved(
        "2021-20-20", new ParsePosition(0)
    )
);

DateTimeException 也是 parseUnresolved 可以抛出的 documented 异常。

Throws:

DateTimeException - if some problem occurs during parsing

碰巧 parseUnresolved 在“第一阶段”解析偏移量时无法识别任何超过 24 小时的偏移量。