12

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 switch to the default resolve style, i.e. ResolverStyle.SMART it allows such dates as 30th of February.

Can someone please help?

1
  • 3
    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. Commented Dec 13, 2016 at 10:41

2 Answers 2

21

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".

Sign up to request clarification or add additional context in comments.

2 Comments

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;`
also used @DateTimeFormat( iso = DateTimeFormat.ISO.DATE, pattern = "MM-dd-uuuu" ) but effect.
7

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).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.