Issue with DateTimeParseException when using STRICT resolver style
Asked Answered
P

2

8

I am trying to parse a date string using the following pattern: yyMMdd and the STRICT resolver as follows:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat).withResolverStyle(ResolverStyle.STRICT);
LocalDate.parse(expiryDate, formatter);

I get the following DateTimeParseException:

java.time.format.DateTimeParseException: Text '160501' could not be parsed: Unable to obtain LocalDate from TemporalAccessor: {YearOfEra=2016, MonthOfYear=5, DayOfMonth=1},ISO of type java.time.format.Parsed

When I swith to the default resolve style, i.e. ResolverStyle.SMART it allows such dates as 30th of February.

Can someone please help?

Pergola answered 12/12, 2016 at 14:56 Comment(1)
I regret that the java.time-design is not clever enough to recognize that - in absence of era field - the year-of-era (symbol y) should be handled like proleptic gregorian year (symbol u). In addition, the original ISO-8601-paper does not say anything about eras. Therefore a plain year-month-day-combination should really be handled like what ISO says, ignoring the era and using the proleptic gregorian calendar.Coordination
L
18

The strict resolver requires an era to go with YearOfEra. Change your pattern to use "u" instead of "y" and it will work, ie. "uuMMdd".

Locus answered 12/12, 2016 at 15:21 Comment(2)
Hi i used uuuu in place of yyyy but still it allow 02-31-2019. code: ` @FutureOrPresent @DateTimeFormat( iso = DateTimeFormat.ISO.DATE ) @JsonFormat( pattern = "MM-dd-uuuu" ) private LocalDate start;`Manas
also used @DateTimeFormat( iso = DateTimeFormat.ISO.DATE, pattern = "MM-dd-uuuu" ) but effect.Manas
D
4

While JodaStephen has nicely explained the reason for the exception and given one good solution (use uu rather than yy), I am offering a couple of other possible solutions:

  1. The obvious one that you probably don’t want: leave the resolver style at SMART (the default). In other words either leave out .withResolverStyle(ResolverStyle.STRICT) completely or change it to .withResolverStyle(ResolverStyle.SMART).
  2. Provide a default era.

For the second option here is a code example:

    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .appendPattern("yyMMdd")
            .parseDefaulting(ChronoField.ERA, 1)
            .toFormatter()
            .withResolverStyle(ResolverStyle.STRICT);

    String expiryDate = "160501";
    LocalDate result = LocalDate.parse(expiryDate, formatter);
    
    System.out.println(result);

Output is:

2016-05-01

Where the last solution may make a difference compared to using uu in the format pattern:

  1. It allows us to use a format pattern that is given to us where we cannot control whether pattern letter u or y is used.
  2. With pattern letter y it will fail with an exception if the string contains a negative year. Depending on your situation and requirements this may be desirable or unacceptable.

Edit: The second argument to parseDefaulting() may also be written IsoEra.CE.getValue() rather than just 1 to make it clear that we are specifying the current era (CE; also often called Anno Domini or AD).

Decapod answered 2/9, 2020 at 15:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.