Tuesday, March 30, 2010

Java Dates

Hi everybody.
In this post I've decided to discuss the java date's related possible issues.
We will talk about java timezones, dates, switching to the daylight saving time, etc. Recently I had a chance to explore this theme, so here are my thoughts and conclusions. Hope you'll find it useful.
Here we go.
Basically the date as we see it in our computers is comprised of
- The base (GMT == UTC)
- The offset (in hours) that denotes our timezone.
For example Asia/Jerusalem timezone = GMT (base) + 2 (2 hours offset).
The 'base' time is usually taken from the underlying Operating System, but the offset is a tricky part here.
The timezone differs in the different geographical locations in the world, and this is a kind of "static" information. We can always know which timezone we belong to just by our geografical location and its always the same timezone.
The "dynamic" part adds a lot of headache when it comes to switching to the Daylight Saving Time (DST). In different countries governments decide when to switch to the DST (in some countries there is no such a thing at all).
The are two such a switches. Usually on spring we add one hour to our offsets. Somewhere during the autumn we switch back (cancel the DST).
For example (I'll continue with Asia/Jerusalem timezone here):
During the DST period, we'll get
GMT + 3 (3 hours offset)
When the DST is switched off we'll get GMT + 2

So the main question here is when do we switch to the DST back and forth.
And here come some bad news: its not constantly the same time, but rather changes each year (well, at least it can be so). In general case the switch can't be predicted since it can be fulfilled as a result of the government decisions which can be theoretically taken each year. AFAIK in most of the countries its not so, but still we can't refer to this piece of information as a static content.

Ok, now, after some theoretical insights let's get down to the java implementation.

Java has been designed portable language so it should work in the same way on different OSes.
Unix and Linux have a "predefined" table for all the timezones.
Windows on the other hand is aware only of a change within the next year (as far as I understand Windows 7 fixed this behavior and now it more resembles Linux implementation but for those of us who don't have yet Windows 7 on their machines its still relevant :) ).

Java language has a very solid support of dates and times but its implemented in a very specific manner.
So JRE developers come with the following solution:
- The base time is really taken from the underlying OS.
- The offset part is determined from the custom tables that are a part of the JRE distribution.
This (to some extent) resembles Linux implementation. But its important to understand that Java doesn't deal with the Linux Tables/information from the windows registry but decides by itself about the offset and DST on & off periods.
Of course such a design, while provides portability, has its own drawbacks:
- We said that the information about the DST can become obsolete theoretically each year (when the new, unpredictible-beforehands decision comes).
- JRE developers should maintain the information about the timezones and DST switches all over the world and always be up-to-date!

When we're connected to the internet Java can check for the update and offer to download the latest JRE (well, it depends on the JRE installation options, but this is not our main focus here).
However for organizations running the JRE in LAN and those who don't have a direct internet connection it can be a tedious task to update the JRE.

Each version of JRE comes with the up-to-date table of timezones and DST periods (of course which is relevant when the version is published).
It can be found in %{JRE_INSTALLATION_HOME}/lib/zi folder and physically its just a set of binary files (a file for each timezone).
Linux also has such a binary table. Lets see what information can really be found there:
For the current year:

>> zdump -v Asia/Jerusalem | grep 2010

Asia/Jerusalem Thu Mar 25 23:59:59 2010 UTC = Fri Mar 26 01:59:59 2010 IST isdst=0 gmtoff=7200
Asia/Jerusalem Fri Mar 26 00:00:00 2010 UTC = Fri Mar 26 03:00:00 2010 IDT isdst=1 gmtoff=10800
Asia/Jerusalem Sat Sep 11 22:59:59 2010 UTC = Sun Sep 12 01:59:59 2010 IDT isdst=1 gmtoff=10800
Asia/Jerusalem Sat Sep 11 23:00:00 2010 UTC = Sun Sep 12 01:00:00 2010 IST isdst=0 gmtoff=7200

Here by convention UTC means the 'base' time,
IST = Israel Standard Time (the base + offset with the DST switched off)
IDT = Israel Daylight saving Time ( the base + offset with the DST switched on)
The output is 4 lines. The first two lines denote switching the DST on and the last two line show when the DST period will end.

Unlike Linux, Java doesn't allow to directly see the information in the zi directory (no third-party utility is available as far as I know). Moreover Linux allows to extend the table by our own rules (zic - zone info compiler will do that), but Java doesn't.

So how we can influence this information in Java?

- First of all consider to use tzupdater a utility provided my the jre maintainer. I know that Oracle (Sun) provide such a utility for their jre distribution.
This utility is a jar that updates the zi folder with the recent information.
Some Caveats:
- This still doesn't allow to see the current state of the tables
- If you run the old jre version (1.0 - 1.3) you can't use tzupdater. So this solution is applicable only for those of us running the jre 1.4+
- If you're running java on platforms that are not directly supported by Oracle (Sun), for example HP-UX or jrockit, you should consider to download the tzupdater from the site of HP and not from Oracle, the Oracle's tzupdater just won't work.

- Figure out whether your current java distribution is ready for the next DST switch.
There are some methods of doing that:
  • Just change the base time on your machine and see how java reacts.
  • Write a simple java program that prints a date before and after the DST switch.
  • Write a simple java program that prints the current TimeZone and see when the java is supposed to apply the DST switch
I'll provide a simple example of java program that prints out the current date:



The output is as follows:
Tue Mar 30 08:27:52 IDT 2010
It shows that now I have the DST switched on.

The program that prints the current timezone is also fairly simple:




The output (again, I'll stick to Asia/Jerusalem timezone) is as follows:
sun.util.calendar.ZoneInfo[id="Asia/Jerusalem",offset=7200000,dstSavings=3600000,
useDaylight=true,transitions=143,
lastRule=java.util.SimpleTimeZone[id=Asia/Jerusalem,
offset=7200000,dstSavings=3600000,
useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=26,
startDayOfWeek=6,startTime=7200000,startTimeMode=0,
endMode=1,endMonth=8,endDay=13,endDayOfWeek=0,endTime=7200000,
endTimeMode=0]]

One can see the similar information as in the linux zoneinfo table but in the different format.

Any java program can be run with special JVM parameter: -Duser.timezone=_THE_TIMEZONE_
* this works also when using web-start of course.

We should consider using this parameter in the situations when:
- Java is unable to determine the current timezone for some reason (I believe It should get down to wrongPC/Server configurations)
- We have an old jre in our legacy system and don't want to touch it :)
- We want to decide by ourselves what is the needed offset.
The parameter can have one of the possible values:
  • ID of the entry in the java internal time zone table (which is nothing more than the set of rules when to switch to DST on and of and what is the current offset). Example: >>java -Duser.timezone=Asia/Jerusalem MyProg
  • The "Hard-coded" offset value. Example: >>java -Duser.timezone=GMT+2 MyProg
For the list of available IDs I suggest to use the following (again very simple) java program:




Conclusions:
- Java has a portable but quite complicated architecture for the date/time/timezones.
- Java maintains its own timezone table (the set of rules) in a proprietary binary format
- tzupdater should be used in order to provide our jre/jdk distribution with the most up-to-date information
- there is still a way to "force" java to ignore its internal timezone table by means of running the program with -Duser.timezone option

I hope you've found this post helpful.
Thanks a lot for attention
Mark Bramnik

1 comment:

  1. Great effort Mark i appreciate you for this great effort thanks for doing such g8 work keep it up ,,,,,, it is good one ... --Sandeep Pareek

    ReplyDelete