Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Time Zone Database vs IANA data

Tags:

java

timezone

dst

There is a Daylight Savings Time discrepancy between the IANA database and the Java tzdb.dat 2019c database in the Africa/Cassablanca time zone that has me very confused. There may be others but I found this one. From what I can tell the IANA time zone database clearly shows that DST is supported in Morocco (Africa/Casablanca) unfortunately the Java time zone database tzdb.dat in the 2019c release does not agree. This has and will cause me infinite grief. What am I missing here, or have others seen this kind of thing

The IANA table 2019c for Africa/Casablanca

Note: the part of the table below shows that the normal time is UTC+1 and Day light savings time is UTC a slash (/) separates standard and daylight abbreviations

Zone NAME STDOFF RULES FORMAT [UNTIL]

Zone Africa/Casablanca -0:30:20 - LMT 1913 Oct 26

         0:00   Morocco +00/+01 1984 Mar 16
         1:00   -   +01 1986
         0:00   Morocco +00/+01 2018 Oct 28  3:00    
         1:00   Morocco +01/+00

From Oct 28 2018 till present offset is +1 for standard and +0 for daylight savings (a slash (/) separates standard and daylight abbreviations.) STDOFF 1:00 so The amount of time to add to UT to get standard time, without any adjustment for daylight saving this corresponds to UTC +1 that is the current Morocco time. So we take Zone Africa/Casablanca which is UTC and add the offsets +01/+00 depending on Ramadan.'

The test

I wrote a simple Java class to check the 2019c TZDB. This class (shown below) shows that something is wrong with the latest Java time zone data file tzdb.dat file. This test was run using IBM SR5FP40 with the time zone 2019c data file. I had the same results with OpenJDK using a 2019c datafile.

First line from tzdb.dat shows 2019c TZDB 2019cX Africa/Abidjan Africa/Accra Africa/Addis_Ababa Africa/Algiers

Test that shows the problem

Time Zone = Africa/Casablanca Supports Day light Savings time = false Date Mon May 20 00:00:00 WET 2019 is currently in DST false Time zone name Western European Time Time zone ID Africa/Casablanca

A baseline test was also run to show if DST is supported the code will show it.

Time Zone = Europe/Rome Supports Day light Savings time = true Date Mon May 20 00:00:00 CEST 2019 is currently in DST true Time zone name Central European Time Time zone ID Europe/Rome

The code is here for reference

import java.util.*; 
import java.text.SimpleDateFormat;
import java.text.ParseException;

public class checkdaylight{ 

    public static void main(String[] args) 
    { 

        // Create TimeZone object
        //Europe/Rome
        //Pacific/Pago_Pago
        //Africa/Casablanca
        String TimezoneToTest = "Africa/Casablanca";
        System.out.println("Time Zone = " + TimezoneToTest);
        TimeZone obj = TimeZone.getTimeZone(TimezoneToTest); 
        TimeZone.setDefault(TimeZone.getTimeZone(TimezoneToTest)); //to avoid confusion

        // Checking day light time 
        // and displaying the result 
        System.out.println("Supports Day light Savings time  = "
                        + obj.useDaylightTime()); 
        String pattern = "yyyy-MM-dd";
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
        try{
            simpleDateFormat.setTimeZone(TimeZone.getTimeZone(TimezoneToTest));
            Date checkdate = simpleDateFormat.parse("2019-05-20");
            System.out.println("Date " + checkdate.toString()+ " is currently in DST "+ obj.inDaylightTime(checkdate));
         } catch (ParseException e) {
            e.printStackTrace();
        }

        System.out.println("Time zone name " +obj.getDisplayName());
        System.out.println("Time zone ID " + obj.getID());

    } 
} 
like image 587
MRED Avatar asked Dec 18 '22 14:12

MRED


1 Answers

Morocco now on DST permanently

As of October 26, 2018, Morocco switched to DST permanently.

The Morocco government gave only 2 days notice(!), in Decree 2.18.855. Apparently the government intends to stop all clock-shifting, with no more changes for DST nor for Ramadan. This decree means an offset of +01:00 year-round.

This decree also means Morocco is no longer “on DST”. The new-normal is an offset one hour ahead of UTC, whereas in the old days the offset was normally at UTC (an offset of zero hours-minutes-seconds). So notice in the code below that calling ZoneRules::isDaylightSavings returns false nowadays (early 2020).

See Wikipedia for details: Daylight saving time in Morocco.

When I say “permanently”, take that with a grain of salt. Politicians around the world have shown a penchant for frequently changing the offset of their respective time zone(s). This "permanently on DST" is only the latest fad to have caught the fancy of politicians. Always expect further changes.

Avoid legacy date-time classes

You are using terrible date-time classes that were supplanted years ago by the modern java.time classes defined in JSR 310. There is no longer any reason to use those awful legacy classes.

Table of all date-time types in Java, both modern and legacy

java.time

Specify your intended time zone.

ZoneId zCasablanca = ZoneId.of( "Africa/Casablanca" ) ;

Fetch the zone rules.

ZoneRules rulesCasablanca = zCasablanca.getRules() ;

Interrogate the rules that apply for a specific moment in that zone.

ZoneOffset offset = rulesCasablanca.getOffset( Instant.now() ) ;
boolean isDst = rules.isDaylightSavings( instant ) ;

Or collapse that to a single line.

ZoneOffset offset = ZoneId.of( "Africa/Casablanca" ).getRules().getOffset( Instant.now() ) ;

Verify your version of Java.

System.out.println( "Java vendor and version:" ) ;
System.out.println( "    " + System.getProperty("java.vendor") ) ;
System.out.println( "    " + Runtime.version() ) ;

String tzdataVersion = 
    java.time.zone.ZoneRulesProvider
              .getVersions("UTC")
              .lastEntry()
              .getKey() 
;
System.out.println( "tzdata: " + tzdataVersion ) ;
System.out.println( "" ) ;

See this code run live at IdeOne.com.

Java vendor and version:

Oracle Corporation

12.0.1+12

tzdata: 2018g

offset.toString(): +01:00

isDst: false

Specific date

Let's try your specific date.

    LocalDate localDate = LocalDate.parse( "2019-05-20" ) ;
    ZonedDateTime zdt = localDate.atStartOfDay( z ) ;
    System.out.println( "zdt.toString(): " + zdt ) ;
    System.out.println(
        "offset: " + rules.getOffset( zdt.toInstant() ) + 
        "  |  is in DST: " + rules.isDaylightSavings( zdt.toInstant() ) 
    );

zdt.toString(): 2019-05-20T00:00+01:00[Africa/Casablanca]

offset: +01:00 | is in DST: false

tzdata

Oracle lists the tzdata files built into Java runtimes.

That list shows that the Morocco switch to permanent DST was accounted for in tzdata2018g. That tzdata file was bundled with Java versions 11.0.2, 8u201, and 7u211. At least Oracle bundled it, while I assume the OpenJDK project did so as well (I did not verify).

Morocco switches to permanent +01 on 2018-10-27.

Morocco switches from +00/+01 to permanent +01 effective 2018-10-27, so its clocks will not fall back on 2018-10-28 as previously scheduled.

To get the version of the tzdata data file in use by your JVM, see this Answer on the Question, Java - find tzdata version in use regardless of JRE version.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

  • Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
    • Java 9 adds some minor features and fixes.
  • Java SE 6 and Java SE 7
    • Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
  • Android
    • Later versions of Android bundle implementations of the java.time classes.
    • For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

like image 125
Basil Bourque Avatar answered Jan 02 '23 14:01

Basil Bourque