Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DateTimeFormatter parsing - timezone names and daylight savings overlap times

Tags:

java

java-time

For improving performance of some legacy code, I am considering a replacement of java.text.SimpleDateFormat by java.time.format.DateTimeFormatter.

Among the tasks performed is parsing date/time values that had been serialized using java.util.Date.toString. With SimpleDateFormat, it was possible to turn them back into the original timestamps (neglecting fractional seconds), however I am facing problems when attempting to do the same with DateTimeFormatter.

When formatting with either, my local timezone is indicated as CET or CEST, depending on whether daylight savings time is in effect for the time to be formatted. However it appears that at parsing time, both CET and CEST are treated the same by DateTimeFormatter.

This creates a problem with the overlap occurring at the end of daylight savings time. When formatting, 02:00:00 is created twice, for times one hour apart, but with CEST and CET timezone names - which is fine. But at parsing time, that difference can't be reclaimed.

Here is an example:

long msecPerHour = 3600000L;
long cet_dst_2016 = 1477778400000L;
DateTimeFormatter formatter =
    DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy", Locale.ENGLISH);
ZoneId timezone = ZoneId.of("Europe/Berlin");
for (int hours = 0; hours < 6; ++hours) {
    long time = cet_dst_2016 + msecPerHour * hours;
    String formatted = formatter.format(Instant.ofEpochMilli(time).atZone(timezone));
    long parsedTime = Instant.from(formatter.parse(formatted)).toEpochMilli();
    System.out.println(formatted + ", diff: " + (parsedTime - time));
}

which results in

Sun Oct 30 00:00:00 CEST 2016, diff: 0
Sun Oct 30 01:00:00 CEST 2016, diff: 0
Sun Oct 30 02:00:00 CEST 2016, diff: 0
Sun Oct 30 02:00:00 CET 2016, diff: -3600000
Sun Oct 30 03:00:00 CET 2016, diff: 0
Sun Oct 30 04:00:00 CET 2016, diff: 0

It shows that the second occurrence of 02:00:00, inspite of the different timezone name, was treated like the first one. So the result effectively is off by one hour.

Obviously the formatted string has all information available, and SimpleDateFormat parsing in fact honored it. Is it possible to roundtrip through formatting and parsing, using DateTimeFormatter, with the given pattern?

like image 533
Gunther Avatar asked Dec 18 '22 08:12

Gunther


1 Answers

It is possible for a specific case:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    .appendPattern("EEE MMM dd HH:mm:ss ")
    .appendText(OFFSET_SECONDS, ImmutableMap.of(2L * 60 * 60, "CEST", 1L * 60 * 60, "CET"))
    .appendPattern(" yyyy")
    .toFormatter(Locale.ENGLISH);

This maps the exact offset to the expected text. Where this fails is when you need to deal with more than one time-zone.

To do the job properly requires a JDK change.

like image 66
JodaStephen Avatar answered Dec 29 '22 00:12

JodaStephen