by Gili Nachum

Set your Java clocks for the new DST

news
Dec 1, 200612 mins

Solutions for adjusting your Java clock during time changes

When the DST (Daylight Saving Time) period starts or ends, do your Java-powered applications show the wrong time of day or even malfunction? Do your department managers and system administrators break out in a cold sweat whenever they hear “Java” in relation to a clock change? Are your production applications too mission critical to tolerate any downtime or data inconsistencies? Does your application business logic relate to U.S., Israel, or Brazil time zones? Do you want to prevent your application from running one hour behind other applications and services from March 11 till April 1, 2007 due to the new changes in U.S. DST rules?

If you find yourself answering yes to one or more of the previous questions, continue reading to understand how the Java platform handles time, time zones, and DST rules, and what you can do to keep your Java production systems up and running while protected from DST rule changes.

Operating systems’ time zone and DST implementation

In ancient times, an OS administrator would have to manually set the clock for DST; nowadays, operating systems have an internal automatic mechanism for time zones and DST clock adjustments. This mechanism’s moving cogs are the machine hardware clock, the operating system’s local time zone setting, and the OS zoneinfo database, also called the tz database (TZDB).

Machine clocks are always kept in sync with the GMT/UTC, (Greenwich Mean Time/ Coordinated Universal Time; I use these terms interchangeably) using the NTP, or Network Time Protocol. Thus, in practice, all of the world’s servers hold the same universal time.

But users don’t care about GMT; they are more concerned with their local time. To compute the correct local time, the OS needs to know the local time zone in which it operates (OS local time zone settings) and have access to the information provided in the TZDB, which holds international time zone information and DST rules. With this information, the OS can compute and serve the correct local date and time to the user or to a process.

On Linux, the date command (with no arguments) will return local time compute as: GMT_TIME + LOCAL_TIME_ZONE_OFFSET + DST_OFFSET. (If you want to see the bare GMT time with no time zone adjustments use date -u).

The TZDB is a binary compilation of human readable text files; it is your OS administrator’s responsibility to make sure that the TZDB is updated.

The local time zone file is:

  • In Linux: /etc/TIMEZONE
  • In Unix: /etc/localtime

The TZDB resides on:

  • In Linux: /usr/share/zoneinfo/
  • In Unix: /usr/share/lib/zoneinfo/

Java time zone and DST implementation

I came across Java’s DST issue when I was providing application server consulting services for a large Israeli telecom operator. My client had been experiencing many application clock problems around the start and end of the DST period, complaining that the “Java clock,” with a mind of its own, wouldn’t make the hour shift alongside the OS clock.

Sun’s Java Runtime Environment/JDK doesn’t use the OS TZDB; instead, it has its own implementation of time zone information and DST rules. The JRE versions 1.4 and 1.5 implement the time zone and DST definitions in a similar fashion to Unix/Linux. And although the binary formats of an OS’s TZDB and Java’s time zone information differ, they are both compiled from the same TZDB text files.

On all platforms, Java’s TZDB can be found at ${JRE_HOME}/lib/zi/. Version 1.3.X has its TZDB implementation hard-coded into its time framework classes.

The BEA JRockit JVM seems to use the same TZDB as Sun’s JVM (keeping things compatible and simple), while IBM’s JVM doesn’t have a TZDB directory (even for 1.4.X versions).

As you are about to see next, the fact that the TZDB directory is decoupled from the JVM’s classes and code can save us a lot of headaches.

The problem: A stale TZDB

Java’s TZDB specification is quite flexible; it can apply a different DST rule for each year for each time zone (e.g., the U.S.’s 2007 DST rule will differ from the 2006 rule). The problems start when local governments unexpectedly change future DST rules, thus making the current DST rules in Java’s TZDB obsolete. In countries like Israel and Brazil, this problem occurs almost yearly. Australia had the same problem when it changed its local DST settings in 2006 (see “Australian Time Zone Changes Affect Java Applications“). U.S. time zone DST rules will also become outdated due to the Energy Policy Act of 2005 (see “U.S. Daylight Saving Time Changes in 2007“): staring in 2007, the U.S. DST will last one month longer.

An outdated DST rule causes the JVM to add/subtract the DST time “delta” (usually one hour) at the wrong point in time, either sooner or later than expected. This will cause the JVM, and hence the application, to be out of sync with the underlying OS time (assuming the OS TZDB is updated) and other outside services, which can produce unexpected results ranging from an incorrect timestamp log entry to certain services ceasing to operate, or even a complete application failure.

So now that you are fully convinced that an updated TZDB is a desired goal, what can we do to keep it updated?

Keeping the TZDB updated: What are my options?

Consider the following options and solutions:

Do nothing: If your application isn’t time and date sensitive and has little interaction with the OS or other services, you might decide that doing nothing is best. Testing beforehand is always advisable (moving the clock backward/forward and analyzing the outcome). Another case where you might choose to take no action is when the new and old DST start/end dates are very close. For example, in Israel in 2006, the outdated JVM DST period ended exactly one hour before the OS DST period. In such a case, you might plan a scheduled system downtime to sleep throughout the problematic one-hour period.

Manually set the user.timezone JVM system property: When the JVM starts, it uses its native libraries to determine the OS time zone and set the user.timezone system correctly. For example, if the OS local time zone is set for Israel, the JVM will set the user.timezone property to Asia/Jerusalem. The Java Calendar and Timezone classes use this property to load the correct default time zone information from the TZDB.

It is also possible to explicitly set the user.timezone property, when running Java, as a geographical/state: java -Duser.timezone=Area/City HelloWorld. Or as a generic time zone expressed in numerical hours “delta” from GMT time, thereby skipping the outdated TZDB, where “delta” is the number of hours prior/ahead of GMT time: java -Duser.timezone=GMT[-+delta] HelloWorld. For example, to set a generic time zone that corresponds to Asia/Jerusalem time without DST, we would use GMT+2, and with DST, we would use GMT=+3.

This method has many drawbacks, including the need to update the startup script for every application twice a year and having to restart the JVM at the exact point in time the DST starts/ends. Also, this is not a viable option for an international application that has to relate to many different time zones.

Upgrade the Java Runtime Environment/JDK version: This is the official recommendation from Sun and BEA. By upgrading to the latest JRE, you are actually replacing your old TZDB with an updated, fresh TZDB.

However, upgrading your JRE might not be such an attractive idea. A typical IT department could have dozens of Java applications; each OS could have many JREs installed on it (figure out which is the one in use and then navigate through seven levels of symbolic links); and, of course, replacing the JRE requires a scheduled application downtime. Another more serious problem is receiving vendor approval for upgrading an application’s JVM version. (“We tested the application only with 1.4.1_02! We can’t approve 1.4.2_12 without 2 weeks of load testing for memory leaks!” or “We don’t support 1.5.0_08! Upgrading will mean warranty is off.”) I can’t blame the vendors; I’ve seen applications that have started to crash when launched with ‘-server’ JVM (due to different thread-handling implementations).

Upgrade only the TZDB: Why buy the whole cow when a glass of milk is all you need? This solution is the natural option. Just as we don’t upgrade the OS version when we need to update the TZDB, we should just as well not be forced to upgrade the JVM code. According to the long tests I conducted, replacing the TZDB (i.e., the ${JRE_HOME}/lib/zi/ directory) is a legitimate possibility. Read on to see my results.

Test objectives

I wanted to see if the time zone databases of JRE 1.4 and JRE 1.5 matched, so that a TZDB taken from 1.4 could be plugged into 1.5 and vise versa. If so, this would mean I could download the latest JRE version and plug its TZDB into an existing older 1.4/1.5 JRE, thus profiting from updated DST rules without having to pay the warranty/stability/compatibility price of a new JRE version. I also wanted to know if I could update only specific time zone files in the TZDB for an application that only relates to specific local time.

Definitions and axioms:

  1. An updated TZDB: One with DST rules stating that the Asia/Jerusalem DST period ends at 01/10/2006, 02:00 a.m. (jumping back to 01:00 at 02:00). Located at: C:Program FilesJavajdk1.5.0_06jrelibzi.
  2. A stale TZDB: One with DST rules stating that the Asia/Jerusalem DST period ends at 01/10/2006, 01:00 a.m. (jumping back to 00:00 at 00:00). Located at: C:Program FilesJavaj2sdk1.4.0jrelibzi.
  3. An updated JRE: Sun’s JDK 1.5.0_06 contains an updated TZDB.
  4. Legacy JRE: JDK 1.4.0 contains a stale TZDB.
  5. Test program: Compares Asia/Jerusalem time zone with an artificial GMT+3, no DST time zone at the critical point in time that tells the updated and stale TZDBs apart.

Test procedure:

  1. Action: Ran the test program using the legacy JRE. Results: Program reports a stale TZDB.
  2. Action: Ran the test program using the updated JRE. Results: Program reports an updated TZDB.
  3. Actions: Replaced the legacy JRE TZDB with the updated TZDB (copy “…jdk1.5.0_06jrelibzi” directory over “…j2sdk1.4.0jrelibzi”), ran the test program using the legacy JRE. Results: Program reports an updated TZDB.
  4. Actions: Restored all JREs to their original TZDBs, replaced the updated JRE TZDB using the legacy JRE TZDB, ran the test program using the updated JRE. Results: Program reports a stale TZDB.
  5. Action: Same as Steps 3-4, but updated only the “…ziAsiaJerusalem” file and not the entire TZDB. Results were identical.

After running the above test steps on an ad hoc piece of software I wrote, I tested it on an existing OLTP (Online Transaction Processing) Web application test environment, later to be applied to all of the company production application servers.

Conclusions

I conducted more tests, not documented here, that further showed replacing the TZDB (i.e., the ${JRE_HOME}/lib/zi/ directory) as a legitimate possibility for solving our DST issue. The TZDB is fully compatible between all 1.4.X and 1.5.X versions, and also platform independent. It’s probably safer to stop the JVM while you are downloading it, although theoretically, you might presume that it shouldn’t get in the JVM’s way unless a classloader was in the middle of a Timezone classloading operation.

This option is much less intrusive than the JRE upgrade option since only new, trivial data, and not new untested code, is introduced into your delicate, high-availability, demanding application. You might have an easer task convincing your application vendor to approve with the TZDB upgrade.

This solution isn’t an option for IBM 1.4.X and Java 1.3.x versions that don’t have an external TZDB; you should go with a JRE upgrade.

Another option is to switch over to Joda-Time, an easy-to-use open source Java date and time API that provides a quality replacement for the Java date and time classes. The design allows for multiple calendar systems, while still providing a simple API. In addition to the Gregorian Calendar, the Julian, Buddhist, Coptic, and Ethiopic systems are also included. It also claims to have better performance characteristics then the vanilla Java.util date and time. It also features a separate TZDB that can be updated as needed, thus further decoupling the JRE and TZDB.

Fixing the time warp

What can be done to overcome the stale DST rules problem? How can Java change and grow to overcome this maintenance issue?

Should every programming and scripting platform implement and maintain its own TZDB? I sure don’t think so. The OS has its own TZDB. I believe the JVM, being a native OS component as it is, should be allowed to utilize the existing OS TZDB (this option could be switch on/off via a special -X startup argument). Some platforms like mobile phones or other devices might not have an internal updated TZDB. But true mission-critical applications run on standard operating systems, and Sun should provide them with precedence. Regardless, this solution should only be an option, not mandatory.

A TZDB update utility could be provided: just auto download only the TZDB without the JRE and utilize existing update mechanisms like JavaUpdate in Windows or RPM/up2date/yum in Linux. Or a way to hot deploy a TZDB into the JVM could be offered, either through a classloader reloading or through specially crafted logic. I hope this functionality could be included in future versions of Java.

I believe that alongside the original JRE/JDK 1.3.x_y versions, Sun should provide the same JRE/JDK 1.3.x_y version with an up-to-date TZDB. That way, we could update a production environment without introducing new code into the ecosystem. (Note: In 1.3, the TZDB is indeed hard-coded into the code, but it is concentrated in a specific area. Thus, changing it won’t really introduce new code.) Sun should provide a way to overcome the 1.3 TZDB design compromise while keeping production environments free of new code.

Gili Nachum works as a senior software architect at db@net, a company that provides IT architecture solutions and services. Nachum has been writing software since 1996 and programming in Java since 2000. Nahum holds a bachelor’s degree in economics and administration, lives in Israel, and specializes in RTS computer games.