javajava-timetimezone-offsetdatetime-parsingjava.time.instant

java.time.OffsetDateTime: Unable to obtain OffsetDateTime from TemporalAccessor


I'm trying to parse "20140726080320+0400" using "yyyyMMddHHmmssZ" format as follows:

System.out.println("********************" + OffsetDateTime
    .parse("20140726080320+0400",
        DateTimeFormatter.ofPattern("yyyyMMddHHmmssZ").withChronology(IsoChronology.INSTANCE).withResolverStyle(STRICT))
    .toEpochSecond()); 

I keep running into this exception:

java.time.format.DateTimeParseException: Text '20140726080320+0400' could not be parsed: Unable to obtain OffsetDateTime from TemporalAccessor: {OffsetSeconds=14400, DayOfMonth=26, YearOfEra=2014, MonthOfYear=7},ISO resolved to 08:03:20 of type java.time.format.Parsed
    at java.time.format.Parsed.getLong(Parsed.java:203)
    at java.time.Instant.from(Instant.java:373)
    at java.time.OffsetDateTime.from(OffsetDateTime.java:365)
    at java.time.format.Parsed.query(Parsed.java:226)
    at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)
    at java.time.OffsetDateTime.parse(OffsetDateTime.java:402)

What am I doing wrong?


Solution

  • yyyy in the format pattern string is for year of era. Strictly speaking, 2014 could denote 2014 BCE (“before Christ”) or 2014 CE (“anno Domini”). Apparently the formatter with strict resolver style objects to this ambiguity.

    A solution is to use uuuu for year. This is a signed year where 0 means 1 BCE, -1 means 2 BCE etc. So there is no ambiguity:

        System.out.println("********************"
                + OffsetDateTime.parse("20140726080320+0400",
                                    DateTimeFormatter.ofPattern("uuuuMMddHHmmssZ")
                                            .withChronology(IsoChronology.INSTANCE)
                                            .withResolverStyle(STRICT))
                            .toEpochSecond());
    

    This prints

    ********************1406347400

    This is related to the way IsoChronology resolves the date for different resolver styles, as described in the javadoc:

    If only the YEAR_OF_ERA is present, and the mode is smart or lenient, then the current era (CE/AD) is assumed. In strict mode, no era is assumed and the YEAR_OF_ERA is left untouched.