Parse week-based-year and week-of-week-based-year without separator character fails
Asked Answered
N

1

7

I'm trying to parse a week-based-year and week-of-week-based-year from a string without any separator character. E.g. "201812" (week 12 of year 2018). Like this:

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

But this gives me:

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

If I add a space between the fields like so:

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

It works fine, with result:

2018-01-15

Is this another bug like this one? Or am I missing something?

The workaround I found was building a custom formatter:

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();
Nahuatlan answered 15/1, 2018 at 15:43 Comment(0)
P
4

This is a known bug which has been fixed for Java-9.


If you are still on Java-8 and cannot move to Java-9 then

  • you are either out of luck

  • or you can use a 3rd-party-library.

Joda-Time: (uses "x" for week-based-year)

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

A replacement for parseDefaulting() is not available.

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

The replacement for parseDefaulting() can be achieved if you set up the formatter not for the type CalendarWeek but the basic type PlainDate and use this general formatter method withDefault(...). Example:

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();
Polygamy answered 15/1, 2018 at 18:9 Comment(3)
Of couse, the simplest workaround would just be parsing the extended ISO-notation: input.substring(0, 4) + "-" + input.substring(4) but I have left it out of my answer because I assume that you look for a library-based solution.Polygamy
Thanks a lot! Good to know it's a bug. I actually did find a workaround (I edited my question to add it).Nahuatlan
@Nahuatlan Fine, the builder approach is also good because it instructs the parser to only parse 4 digits for the week-based-year, not more.Polygamy

© 2022 - 2024 — McMap. All rights reserved.