首页 > 解决方案 > 当所有字段(包括分隔符,但不包括年份)都是可选的时,在 Java8 中解析 ISO 8601 日期

问题描述

我需要在 Java 中以不同的精度解析 ISO8601 格式的字符串。我需要解析的字符串的一些示例是:

如果我没有字段,那么我可以自由假设适用的最低有效值(例如,如果缺少月份,我可以假设 1 月,如果缺少日期,则假设当月的第一天,如果时间失踪假设午夜)

我搜索了 SO,我发现的所有示例都假设我事先知道确切的格式。

标签: javajava-8

解决方案


好吧,我花了比我预期的更长的时间。唯一有效的解析器是:

DateTimeFormatter dtf = new DateTimeFormatterBuilder()
        .appendValue(ChronoField.YEAR, 4)
        .appendPattern("[['-']MM[['-']dd[['T']HH[[':']mm[[':']ss['.'SSS]]]]]]")
        .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
        .parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
        .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
        .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
        .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
        .parseDefaulting(ChronoField.NANO_OF_SECOND, 0)
        .toFormatter();

String[] s = {
        "2018",
        "2018-10",
        "2018-10-15",
        "2018-10-15T12:00",
        "2018-10-15T12:00:30",
        "2018-10-15T12:00:30.123",
        "20181015",
        "201810151200",
        "20181015120030",
        "20181015120030.123",
        "20181015T12:00:30.123"
};
for (String line : s) {
  System.out.println(LocalDateTime.parse(line, dtf));
}

问题是yyyy创建了一个ValueParser(minWidth=4, maxWidth=19, SignStyle.PAD_EXEEDS)解析日期20181015year=20181015例子。所以我们必须将数字宽度限制year为 4。

该文档指出:

Year:字母数决定了使用填充的最小字段宽度。

但没有指定最大宽度。


推荐阅读