Search code examples
javadatejava-8java-11datetimeformatter

Why date parsing using DateTimeFormatter gives different result depending on Java version


Same code of date parsing show different results depending if I am using Java 8 or Java 11.

Here are a code sample to reproduce the problem :

    public static void main(String[] args) {

    DateTimeFormatterBuilder dfBuilder = new DateTimeFormatterBuilder()
            .appendPattern("uuuu-M-d")
            .optionalStart()
            .optionalStart().appendLiteral(' ').optionalEnd()
            .optionalStart().appendLiteral('T').optionalEnd()
            .appendValue(ChronoField.HOUR_OF_DAY)
            .optionalStart()
            .appendLiteral(':')
            .appendValue(ChronoField.MINUTE_OF_HOUR)
            .optionalStart()
            .appendLiteral(':')
            .appendValue(ChronoField.SECOND_OF_MINUTE)
            .optionalStart()
            .appendFraction(ChronoField.NANO_OF_SECOND, 1, 9, true)
            .optionalEnd()
            .optionalEnd()
            .optionalEnd()
            .appendPattern("[XXXXX][XXXX][XXX][XX][X]")
            .optionalEnd();
    DateTimeFormatter df = dfBuilder.toFormatter(Locale.FRANCE).withZone(ZoneId.of("Europe/Paris"));

    TemporalAccessor temporalAccessor = df.parse("1970-01-01T00:00:00.00Z");
    Instant instantTime = Instant.from(temporalAccessor);
    long epochTimestamp = instantTime.getEpochSecond();
    System.out.println(epochTimestamp);
}

On java 8 the output is -3600.

While on Java 11 the output is 0 (which is the value I am expecting).

From my analysis the origin is the use of "withZone()" method, if I remove it, it works as expected for dates that contains zone data.

But at the same this behavior is not the same on all DateTimeFormatter : for example if I use this formatter :

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
                .appendPattern("yyyy-MM-dd HH:mm:ss")
                .appendFraction(ChronoField.MICRO_OF_SECOND, 0, 6, true)
                .optionalStart()
                .appendZoneId()
                .optionalEnd()
                .toFormatter()
                .withZone(ZoneId.of("Europe/Paris"));

The zoneId is well taken into account in case present inside the date (despite the fact "withZone() is called). So I suppose there is something wrong with the first formatter and that a default behavior on Java 11 helps it to work as expected on Java 11 but not on Java 8 ? Also I precise that my goal is to have it works on Java 8.


Solution

  • Known bug

    It’s a known bug in Java 8. Parsing with DateTimeFormatter.withZone does not behave as described in javadocs.

    Funnily the bug report in the Java Bugs System that I link to does not mention a fix version. It does mention that the bug is not in JDK 9-ea, though:

    To reproduce the issue, run the attached test case. It fails on JDK 8u121 but passes in JDK 9-ea.