Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

java

localdate

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();
like image 279
fassen Avatar asked Jan 15 '18 15:01

fassen


People also ask

What is week based year?

All weeks in the ISO-8601 Week-Based calendar have exactly 7 days, start on a Monday, and each week belongs to single year. Unlike the Gregorian calendar, there are no weeks that extend across years. Each ISO-8601 year is either a Long or a Short year, with 52 or 53 weeks depending on when the ISO-8601 year begins. Day.

What is the difference between year and week year?

“Week year” is intended to be used for week dates, e.g. “2015-W01-1”, but is often mistakenly used for calendar dates, e.g. 2014-12-29, in which case the year may be incorrect during the last week of the year. If you are formatting anything other than a week date, you should use the year specifier “yyyy” instead.

What is basic_ ISO_ date?

BASIC_ISO_DATE. The ISO date formatter that formats or parses a date without an offset, such as '20111203'. static DateTimeFormatter. ISO_DATE. The ISO date formatter that formats or parses a date with the offset if available, such as '2011-12-03' or '2011-12-03+01:00'.

Which of the following date/time formatter pattern can be used to print the date in the below format?

Explanation of the pattern dd-MM-yy hh.


1 Answers

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();
like image 153
Meno Hochschild Avatar answered Oct 11 '22 00:10

Meno Hochschild