3

我必须使用以下格式解析日期:“201710”其中 10 - 一年中的第几周。我试图以这种方式实现它:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyw");
java.time.LocalDate startDate = java.time.LocalDate.parse("201710", formatter);
System.out.println(startDate);

但它抛出异常:

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

之后,我需要从 LocalDate 对象获取一周的第一天和最后一天。例如“201710” - 05.03 12.03(一周的第一天必须是星期日)。

4

3 回答 3

4

@Kayaman 接受的答案不正确,因为您不能混合标准日期表示(使用 yyyy = 年份)和周日期表示(使用 ww = 基于周的年份)。标准日历年和基于周的年之间的细微差别在日历年的开始或结束时是相关的。结论:不要使用符号“y”,而应使用符号“Y”。输入“201501”的反例:

正确的解决方案

DateTimeFormatter formatter =
    new DateTimeFormatterBuilder()
    .appendValue(WeekFields.ISO.weekBasedYear(), 4)
    .appendValue(WeekFields.ISO.weekOfWeekBasedYear(), 2)
    .parseDefaulting(ChronoField.DAY_OF_WEEK, 1)
    .toFormatter();
LocalDate startDate = LocalDate.parse("201501", formatter);
System.out.println(startDate); // 2014-12-29

基于@Kayaman 的提议:

DateTimeFormatter dtf =
    new DateTimeFormatterBuilder()
    .appendValue(ChronoField.YEAR, 4)
    .appendValue(ChronoField.ALIGNED_WEEK_OF_YEAR, 2)
    .parseDefaulting(WeekFields.ISO.dayOfWeek(), 1)
    .toFormatter();
System.out.println(LocalDate.parse("201501", dtf)); // 2015-01-05 (wrong)

结果日期不同!差异是由日历年的定义引起的,日历年总是从一月一日开始,而基于周的年总是从星期一开始(ISO-8601 定义),使用日历年的第一周,至少有 4 天。

附加说明 a): Java-8 不管理可本地化字段的相邻数字解析,例如基于周的字段(另请参阅相关的JDK 问题),因此我选择了基于构建器的解决方案,而不是定义模式“YYYYww”(然而,Java-9 承诺提供一个解决方案)。但即使使用 Java-9,仍然需要基于构建的方法,因为需要为缺少的星期几定义默认值(此处:设置为星期一)。

附加说明 b):如果您正在寻找基于周的年份和年份的组合的真正类型,并且LocalDate仅用作这种缺失类型的解决方法,那么您可以在 3rd-party 中找到这样的类型库,在 Threeten-Extra 或我的库Time4J中。例子:

    ChronoFormatter<CalendarWeek> cf =
        ChronoFormatter.ofPattern(
            "YYYYww",
            PatternType.CLDR,
            Locale.ROOT,
            CalendarWeek.chronology()
        );
    CalendarWeek cw = cf.parse("201501");
    System.out.println(cw); // 2015-W01
    System.out.println(cw.at(Weekday.MONDAY)); // 2014-12-29
于 2017-03-24T11:23:04.093 回答
2

如果值之间有空格,则(先前的)重复项有效,但是如果没有空格,则以下内容可以很好地解析。

DateTimeFormatter dtf = new DateTimeFormatterBuilder()
        .appendValue(ChronoField.YEAR, 4)
        .appendValue(ChronoField.ALIGNED_WEEK_OF_YEAR, 2)
        .parseDefaulting(WeekFields.SUNDAY_START.dayOfWeek(), 1)
        .toFormatter();

System.out.println(LocalDate.parse("201710", dtf));
// 2017-03-05

替换SUNDAY_STARTwithISO会给你从星期一开始的几周(所以它会打印2017-03-06)。

于 2017-03-23T14:46:58.560 回答
1
于 2018-10-01T00:28:56.330 回答