解析没有分隔符的基于周的年份和基于周的年份失败

Parse week-based-year and week-of-week-based-year without separator character fails

我正在尝试从没有任何分隔符的字符串中解析基于周的年份和基于周的年份。例如。 “201812”(2018 年第 12 周)。像这样:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
                                    .appendPattern("YYYYww")
                                    .parseDefaulting(WeekFields.ISO.dayOfWeek(), 1)
                                    .toFormatter();
LocalDate parse = LocalDate.parse("201803", formatter);

但这给了我:

java.time.format.DateTimeParseException: Text '201803' could not be parsed at index 0

如果我像这样在字段之间添加 space:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
                                    .appendPattern("YYYY ww")
                                    .parseDefaulting(WeekFields.ISO.dayOfWeek(), 1)
                                    .toFormatter();
LocalDate parse = LocalDate.parse("2018 03", formatter);

它工作正常,结果:

2018-01-15

Is this another bug like this one? 还是我遗漏了什么?

我找到的解决方法是构建自定义格式化程序:

DateTimeFormatter yearWeekPattern = new DateTimeFormatterBuilder().appendValue(IsoFields.WEEK_BASED_YEAR, 4)
    .appendValue(IsoFields.WEEK_OF_WEEK_BASED_YEAR, 2)
    .parseDefaulting(WeekFields.ISO.dayOfWeek(), 1)
    .toFormatter();
LocalDate.parse("201803", yearWeekPattern).atStartOfDay(ZoneId.systemDefault()).toInstant();

这是一个 已知错误,已 fixed for Java-9


如果您仍在 Java-8 并且无法移动到 Java-9 那么

  • 你要么运气不好

  • 或者您可以使用第 3 方库。

Joda-Time:(使用 "x" 表示基于周的年份)

DateTimeFormatter formatter =
    new DateTimeFormatterBuilder().appendPattern("xxxxww").toFormatter();
LocalDate joda = LocalDate.parse("201803", formatter);
System.out.println(joda); // 2018-01-15

parseDefaulting() 的替代品不可用。

Time4J (my lib):

ChronoFormatter<CalendarWeek> f =
    ChronoFormatter.ofPattern(
        "YYYYww",
        PatternType.CLDR,
        Locale.ROOT,
        CalendarWeek.chronology()
    );
CalendarWeek cw = f.parse("201803");
java.time.LocalDate d = cw.at(Weekday.MONDAY).toTemporalAccessor();
System.out.println(d); // 2018-01-15

如果您不是为类型 CalendarWeek 而是为基本类型 PlainDate 设置格式化程序并使用此通用格式化程序方法 [=20= ,则可以实现 parseDefaulting() 的替换].示例:

ChronoFormatter<PlainDate> f =
    ChronoFormatter
        .ofDatePattern("YYYYww", PatternType.CLDR, Locale.ROOT)
        .withDefault(PlainDate.DAY_OF_WEEK, Weekday.MONDAY);
PlainDate cw = f.parse("201803");
java.time.LocalDate d = cw.toTemporalAccessor();