LocalDate无法使用'yyyy'解析'ww'

时间:2017-03-23 14:02:53

标签: java datetime-format localdate

我必须使用以下格式解析日期:“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(一周的第一天需要是星期天)。

3 个答案:

答案 0 :(得分: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)

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

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

附加说明b):如果您正在寻找基于周的年份和周年组合的真实类型,请使用LocalDate作为解决方法缺少类型,你可以在第三方库中找到这样的类型,可以在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

答案 1 :(得分:2)

如果值之间有空格,则(上一个)duplicate可以正常工作,但是如果没有空格则以下内容会很好地解析。

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_START替换为ISO将为您提供从星期一开始的周数(因此会打印2017-03-06)。

答案 2 :(得分:1)

ThreeTen-Extra

ThreeTen-Extra项目为 java.time 类添加了功能。

YearWeek

该库提供了YearWeek类,可能对您有用。此类使用ISO 8601标准definition of a week

如果可能,我建议您更改自己的字符串以使用标准格式:yyyy-Www,例如2018-W07。默认情况下,YearWeek类使用标准格式来生成/解析字符串。

YearWeek yw = YearWeek.parse( "2018-W07" );

但是,如果您坚持使用自己的非标准格式,则我们必须定义自己的DateTimeFormatter以匹配您的输入。我从YearWeek.java source code中提取了YearWeek.parse方法的一行,并通过禁用两个方法调用对其进行了修改以适合您的情况。

DateTimeFormatter f =
new DateTimeFormatterBuilder()
// .parseCaseInsensitive()
.appendValue( WEEK_BASED_YEAR , 4 , 10 , SignStyle.EXCEEDS_PAD )
// .appendLiteral("-W")
.appendValue( WEEK_OF_WEEK_BASED_YEAR , 2 )
.toFormatter();

尝试一下。

YearWeek yw = YearWeek.parse( "201807" , f );
  

yw.toString():2018-W07


关于 java.time

java.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendarSimpleDateFormat

目前位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310

您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*类。

在哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

相关问题