3
votes

I get wrong time zone name for specific historical dates with negative DST offset.

Update in Time Zone database (tzdata) introduced negative DST for zone Europe/Prague in period from 1946-12-01 to 1947-02-23.

This is the source of tzdata for Europe/Prague:

# We know of no English-language name for historical Czech winter time;
# abbreviate it as "GMT", as it happened to be GMT.

...

            1:00    Czech   CE%sT   1946 Dec  1  3:00
# Vanguard section, for zic and other parsers that support negative DST.
            1:00    -1:00   GMT 1947 Feb 23  2:00
# Rearguard section, for parsers that do not support negative DST.
#           0:00    -   GMT 1947 Feb 23  2:00

This new database is in Java 8 since u181.

When use time in specified period I get wrong time zone name as "CET" / "Central European Time" instead of GMT as is stated in tzdata.

Long timeInMilis = Long.parseLong("-725328000000");
String pattern = "yyyy-MM-dd HH:mm:ss zzz";
TimeZone.setDefault(TimeZone.getTimeZone(("Europe/Berlin")));
System.out.println(new SimpleDateFormat(pattern).format(new Date(timeInMilis)));
TimeZone.setDefault(TimeZone.getTimeZone(("Europe/Prague")));
System.out.println(new SimpleDateFormat(pattern).format(new Date(timeInMilis)));

Result is

1947-01-07 01:00:00 CET
1947-01-07 00:00:00 CET

First row is for Berlin time zone, second for Prague. Both says it's CET, but for Prague it is wrong. It should say GMT as is mentioned in Time Zone Database

1
The reason is probably that zone names are not taken directly from the applicable row in the tzdata, but rather from the TimeZone object, which doesn't know what the date is. If you think this behavior is wrong, you might want to file a bug - though the chances are it will only be fixed for the java.time classes. - RealSkeptic
Note that Long.parseLong("-725328000000") should be written as just -725328000000L. - VGR
Or better still 725_328_000_000L (also @VGR) - Ole V.V.
I recommend you don’t use TimeZone, SimpleDateFormat and Date. Those classes are poorly designed and long outdated, SimpleDateFormat in particular notoriously troublesome. Instead use Instant, ZoneId, ZonedDateTime and DateTimeFormatter, all from java.time, the modern Java date and time API. - Ole V.V.

1 Answers

3
votes

At least as far as I can see in the history of this issue for OpenJDK...

https://bugs.openjdk.java.net/browse/JDK-8195595?page=com.atlassian.jira.plugin.system.issuetabpanels%3Aall-tabpanel

...OpenJDK has avoided dealing with negative DST so far by using the "rearguard" version of tzdata, the version that has no negative DST (an option which apparently will soon be going away).

I suspect that Oracle's Java has been has been avoiding dealing with negative DST so far too.

At any rate, I don't think Java's implementation of timezones handles these timezone abbreviations very well. I tried this bit of sample code:

    SimpleDateFormat  format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss zzz");

    format.setTimeZone(TimeZone.getTimeZone(("Europe/Prague")));

    for (int date = 1; date <= 28; ++date) {
      System.out.println(format.format(new GregorianCalendar(1947, 1, date, 0, 0).getTime()));
    }

...and the designation stays "CET" before and after supposed transition date.

...
1947-02-20 05:00:00 CET
1947-02-21 05:00:00 CET
1947-02-22 05:00:00 CET
1947-02-23 06:00:00 CET
1947-02-24 06:00:00 CET
1947-02-25 06:00:00 CET
1947-02-26 06:00:00 CET
...

If I'm remembering correctly, Java's implementation of timezones doesn't retain the historical record of these abbreviation changes at all, it just encodes transition times for changes in timezone offset. The abbreviations displayed are rendered according to current, not historical, standards.

Edit: I read the tzdata wrong before and was mistaken about what it meant!