4
votes

I have a date formatted in the following way :

The year in four digits then the week number in two digits.

For instance, the fourth week of 2018 will be 201804.

I'm having trouble parsing these dates using Java 8's LocalDate and DateTimeFormatterBuilder.

Here is how I try to parse the date :

LocalDate.parse(
    "201804",
    new DateTimeFormatterBuilder().appendPattern("YYYYww").parseDefaulting(WeekFields.ISO.dayOfWeek(), 1).toFormatter()
);

The execution throws the following exception :

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

The odd behavior is that, when I add a separator between the date parts, the exception is not thrown anymore :

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

Results in :

2018-01-22

Is there a thing I am missing with the formatter ?

4
the fourth week of 2018 or 2019??Vishwa Ratna

4 Answers

5
votes

You can use appendValue

This method supports a special technique of parsing known as 'adjacent value parsing'. This technique solves the problem where a value, variable or fixed width, is followed by one or more fixed length values. The standard parser is greedy, and thus it would normally steal the digits that are needed by the fixed width value parsers that follow the variable width one.

No action is required to initiate 'adjacent value parsing'. When a call to appendValue is made, the builder enters adjacent value parsing setup mode.

So this works:

LocalDate.parse(
                "201804",
                new DateTimeFormatterBuilder()
                        .appendValue(YEAR, 4)
                        .appendValue(ALIGNED_WEEK_OF_YEAR, 2)
                        .parseDefaulting(WeekFields.ISO.dayOfWeek(), 1).toFormatter()
        );
2
votes

Try explicitly defining chrono-fields:

DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder();
DateTimeFormatter formatter = 
      builder.appendValue(ChronoField.YEAR, 4)
             .appendValue(ChronoField.ALIGNED_WEEK_OF_YEAR, 2)
             .parseDefaulting(ChronoField.DAY_OF_WEEK, 1)
             .toFormatter();

LocalDate.parse("201804", formatter);
0
votes

Yea, this also killed me a lot of times with data from foreign sources....

Depending on what you get, you need different parsers. For a Date you need LocalDate and for something with a time you need LocalTimedate.parse.

Meaning if you don't know what data you get(common that current day is without date but with time and on the other hand dates in the past without time but with date - so you don't know), you have to first do a rough parse yourself in order to detect the particular format and only after that Java let parse it.... Javas Date handling is imho a little difficult.

So solution is: use LocalDate instead of LocalTimeDate.

0
votes

Wouldn't simply doing this work?

LocalDate.parse("2018041", DateTimeFormatter.ofPattern("YYYYwwe"));

Essentially you need to tell it you want the date for Monday of that week, not just the week.