Java Time's week-of-week-based-year pattern parsing with DateTimeFormatter
Asked Answered
Y

1

4

I need to output the current date in the format week-based-year-week-of-week-based-year, i.e. using the ISO week date where the week always starts on a Monday and the first week of the year is the first one that has at least four days in January (so the week with the first Thursday in January).

Since 31 December 2015 was a Thursday, the Friday through Sunday, i.e. 1st through 3rd of January 2016, all belong in the 53rd week of 2015 (a "long year"), and the first week of 2016 starts on Monday, 4 January.

From the DateTimeFormatter spec, I would have expected that I can just use the pattern YYYY-ww to do that (Y is week-based-year and w is week-of-week-based-year).

However, when I try something like the following simplified test case:

String dateString = "2016-01-03";
LocalDate date = LocalDate.parse(dateString, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
String expectedOutput = "2015-53";
String actualOutput = date.format(DateTimeFormatter.ofPattern("YYYY-ww"));
System.out.println("Parsing " + dateString + ", expected "
        + expectedOutput + " but got " + actualOutput);
System.out.println(dateString + " as ISO week date: "
        + date.format(DateTimeFormatter.ISO_WEEK_DATE));

I get this:

Parsing 2016-01-03, expected 2015-53 but got 2016-02

2016-01-03 as ISO week date: 2015-W53-7

So using the built-in ISO_WEEK_DATE formatter does what I expected, but using the pattern YYYY-ww seems to give me the calendar year and week.

Have I misunderstood something about ISO week dates, or is there an error in my code, or... dare I say it... is this a bug in the java.time library (as was the case for this question)?

I know I could work around this using a custom formatter like below, but in my case I really need this to work using a pattern.

new DateTimeFormatterBuilder()
    .parseCaseInsensitive()
    .appendValue(IsoFields.WEEK_BASED_YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
    .appendLiteral("-")
    .appendValue(IsoFields.WEEK_OF_WEEK_BASED_YEAR, 2)
    .toFormatter();
Yuri answered 20/9, 2016 at 1:25 Comment(0)
V
4

The documentation of DateTimeFormatterBuilder specifies that "Y" appends the localized week-based year. Thus, the meaning of the week-based year and week fields will depend on the locale set in the formatter.

Vasoinhibitor answered 20/9, 2016 at 5:6 Comment(2)
Ok, interesting - the DateTimeFormatter spec doesn't mention locales coming into play. So what do I do in order to get the ISO-8601 "week-of-week-based-year" that I'm after? If I set my own locale ("en-AU", via DateTimeFormatter.ofPattern("YYYY-ww").withLocale(Locale.getDefault())), which uses this ISO format, I still get the same result.Yuri
Actually, I just tried locales GERMANY and FRANCE, and in both cases I get the expected 2015-53. I was pretty sure that using Sunday instead of Monday as the first day of the week (which would explain why it thinks the 3rd of Jan was week 2) was just a US thing. But thanks, I can work with that!Yuri

© 2022 - 2024 — McMap. All rights reserved.