4

I am migrating an application from jdk 8 to 11 and I can see ZonedDateTime change is behavior about daylight saving time. JDK8

        ZonedDateTime parse = ZonedDateTime.parse("2037-05-10T19:15:00.000+01:00[Europe/Paris]");
        System.out.println(parse);

output: 2037-05-10T19:15+02:00[Europe/Paris]

JDK11/12

        ZonedDateTime parse = ZonedDateTime.parse("2037-05-10T19:15:00.000+01:00[Europe/Paris]");
        System.out.println(parse);

2037-05-10T20:15+02:00[Europe/Paris]

Can someone explain to me why did they change this behavior ?

Best regards,

user2864342
  • 43
  • 1
  • 6
  • Using AdoptOpenJDK 11.0.3 I get `2037-05-10T20:15+02:00[Europe/Paris]` – Robert May 22 '19 at 10:56
  • [are you sure?](https://ideone.com/MLF4HT) – Eugene May 22 '19 at 10:58
  • sorry I haved mix up my snippet. So using Jdk11/12 it does add one hour because of summer daylight saving. And on jdk 8 it is the same datetime 2037-05-10T19:15:00 – user2864342 May 22 '19 at 11:06
  • 4
    It seems that EU will probably abandon summer time (DST) in 2021. Do you know whether Paris will be at offset +01:00 or +02:00 in October 2037? My suspicion would be that it hasn’t been decided yet. – Ole V.V. May 22 '19 at 11:10
  • @OleV.V. exactly my suspicion too, thx for confirming – Eugene May 22 '19 at 11:14
  • 1
    The underlying time zone database has changed between the two releases that you're using. Follow [this question](https://stackoverflow.com/a/41775223/733345) to see what version of the database you're using, then search [the tz-announce archive](https://mm.icann.org/pipermail/tz-announce/) to see what changed between those versions. – Joe May 22 '19 at 11:16
  • awesome thank you guys – user2864342 May 22 '19 at 11:19
  • Thanks, @Joe. However that doesn’t seem to be enough to explain why reportedly both Java versions think Paris will be at offset +02:00, but still the times differ by an hour. – Ole V.V. May 22 '19 at 11:22

1 Answers1

11

It’s a known bug in Java 8: JDK-8066982

I believe that what you are experiencing in Java 8 is really this bug: ZonedDateTime.parse() returns wrong ZoneOffset around DST fall transition. The bug title doesn’t tell the whole story. The real issue is that in Java 8 DateTimeFormatter.ISO_ZONED_DATE_TIME (which is implicitly used by the one-arg ZonedDateTime.parse that you use) ignores the offset if a time zone ID is included in the parsed string. This in combination with a time zone database that disagrees with your string about the offset used in Paris in October 2037 causes a moment in time to be parsed that conflicts with the offset in the string.

The bug is fixed in Java 9. So in Java 9, 10 and 11, since the same disagreement about offset is still there, the moment parsed is based on the offset of the string. It is then converted to the time zone from the string using the rules from the time zone database. This causes the offset to be changed from +01:00 to +02:00 and the hour of day correspondingly from 19:15 to 20:15. I agree with Java 9+ that this is the correct behaviour.

Don’t use ZonedDateTime for far-future dates

Your problem is also partly caused by using ZonedDateTime for a future date. This is only recommended for the very near future where we assume that no zone rules are changed. For a date and time in 2037, you should either use an Instant if you know the moment in time, or a LocalDateTime if you know just the date and time of day. Only when the time draws near and you trust that your Java installation has got the last time zone updates, convert to a ZonedDateTime.

As has been discussed in the comments, we probably don’t know the correct UTC offset for Paris in October 2037 yet. It seems that EU is likely to abandon summer time (DST) from 2021, and as far as I know, the French politicians have not yet decided what the time will be in France after that.

What if we wanted the time of day from the string?

To get the time from the string (19:15), parse into a LocalDateTime:

    String zdtString = "2037-05-10T19:15:00.000+01:00[Europe/Paris]";
    LocalDateTime dateTime
            = LocalDateTime.parse(zdtString, DateTimeFormatter.ISO_ZONED_DATE_TIME);
    System.out.println("Date and time from string: " + dateTime);

Output is (run on Java 11):

Date and time from string: 2037-05-10T19:15

In case you wanted the full Java 8 behaviour on a later Java version — as I mentioned, it’s not recommended, you shouldn’t use ZonedDateTime here:

    TemporalAccessor parsed = DateTimeFormatter.ISO_ZONED_DATE_TIME.parse(zdtString);
    LocalDateTime dateTime = LocalDateTime.from(parsed);
    ZoneId zone = ZoneId.from(parsed);
    ZonedDateTime java8Zdt = dateTime.atZone(zone);
    System.out.println("Time from string in zone from string: " + java8Zdt);

Time from string in zone from string: 2037-05-10T19:15+02:00[Europe/Paris]

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • 1
    I like that the toString/parse in DST imparity bug was fixed. On the other hand, let's assume that in January I make an appointment for somewhere in April at 10:00+03:00 (already summer time). My government comes up in February, and tells - hey folks, we are abandoning DST, we will forever remain in +02:00 now. April comes, ZonedDateTime.parse returns 09:00+02:00 (that's that JDK11 behavior, if the offset is wrong). JDK8 ZonedDateTime would've returned 10:00+02:00. (1/2) – iwat0qs Mar 26 '22 at 12:45
  • That is, I'll approach my appointment place at 10 (because that's what my ticket/appointment email says), and they'll tell me - sorry, our computer tells us, that you should've been here 1 hour before, now you're too late. Genuine concern: What's the point of ZDT now, when storing Instant would've done the same? (2/2) – iwat0qs Mar 26 '22 at 12:47
  • 1
    @iwat0qs I share your concern, it’s genuine. You may say that the Java 8 `ZonedDateTime` was better suited for future times, but really, I don’t think `ZonedDateTime` is at all. Use a `LocalDateTime` and a zone ID. See [Storing appointments in a SQL database such as Postgres for use with java.time framework](https://stackoverflow.com/questions/64545555/storing-appointments-in-a-sql-database-such-as-postgres-for-use-with-java-time-f). – Ole V.V. Mar 26 '22 at 12:49