Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using new Java 8 DateTimeFormatter to do strict date parsing

I have a simple problem : I want to parse Java strings in format "yyyyMMdd" strictly, so that "19800229" is a valid date, but "19820229" is not. Assume these are AD dates from the normal Gregorian calendar.

I am trying to use the new java.time package from JDK 8 to solve this problem, but it is proving more complicated than hoped. My current code is:

private static final DateTimeFormatter FORMAT = DateTimeFormatter
        .ofPattern("yyyyMMdd").withChronology(IsoChronology.INSTANCE)
        .withResolverStyle(STRICT);

public static LocalDate parse(String yyyyMMdd) {
    return LocalDate.parse(yyyyMMdd, FORMAT);
}

However, parsing a valid date such as "19800228" produces what to me is an incomprehensible error:

java.time.format.DateTimeParseException: Text '19820228' could not be parsed: Unable to obtain LocalDate from TemporalAccessor: {MonthOfYear=2, DayOfMonth=28, YearOfEra=1982},ISO of type java.time.format.Parsed

How do I use java.time.format.DateTimeFormatter to solve my simple use case?

like image 978
0xbe5077ed Avatar asked Oct 15 '14 23:10

0xbe5077ed


1 Answers

Java 8 uses uuuu for year, not yyyy. In Java 8, yyyy means "year of era" (BC or AD) and the error message complains that MonthOfYear, DayOfMonth and YearOfEra is not enough information to construct the date because era is not known.

To fix that, use uuuu in your format string, e.g. DateTimeFormatter.ofPattern("uuuuMMdd")

Or, if you want to keep using yyyy, you can set the default era, e.g.

private static final DateTimeFormatter FORMAT = new DateTimeFormatterBuilder()
            .appendPattern("yyyyMMdd")
            .parseDefaulting(ChronoField.ERA, 1 /* era is AD */)
            .toFormatter()
            .withChronology(IsoChronology.INSTANCE)
            .withResolverStyle(ResolverStyle.STRICT);
like image 193
Jan Soltis Avatar answered Oct 14 '22 21:10

Jan Soltis