JEE 6 and Dates

I’ve been having some problems with dates recently in the application I’m currently working on. I need to be able to specify a date that indicates when a particular piece of information becomes valid. Sounds simple enough, yes? I thought so until I actually came to try and implement it. The problem I faced stemmed from the fact that JSF and JEE in general make some assumptions about time that can make your head spin.

At the heart of the problem was a calendar date chooser and a JSF h:outputText element with a date formatter. When I chose certain dates with the calendar they would be displayed as the day before by the outputText element. For example choosing the 18 Aug 2003 led to the display of 17 Aug 2003. After much searching I eventually discovered the cause of the problem: the calendar (or something in the system at least) was choosing the date based on the time zone that would be in effect on the date that was chosen. This meant that 18 Aug 2003 was specified completely as 18 Aug 2003 00:00:00 BST (BST = British Summer Time == UTC+1). However, the h:outputText element, unless told differently, always displays time in GMT (UTC+0). The result of this is that it appears that the time has been incorrectly stored as the day prior to the one chosen.

I thought at first that I must be over thinking the problem as I couldn’t find much on the Internet about it but once I got the right keywords I found hundreds of posts from people with the same problem (see references). The problem I was having was somewhat exacerbated by the fact that I’m using a MySQL database. At some point back in the depths of time it would appear that whoever wrote the date and time fields for MySQL didn’t think to include time zone information – this came as quite a surprise to me since all the other databases I worked with do (somehow I’ve mostly missed working with MySQL despite it’s popularity). Turns out that when dates are written and read to and from MySQL they are converted using the default time zone set in the JVM. This default, unless otherwise set, is picked up from the operating system.

I tried a little experiment: I set the calender to UTC and my system time zone to some far flung country then picked a date. Low and behold the date stored was 8 hours different to the one I’d chosen but it was read out and displayed fine. Here was another problem though, because MySQL doesn’t store time zone information but the dates are interpreted based on the JVM default if the time zone on the server changed the dates would all be interpreted differently! I tried this by setting the OS back to GMT and sure enough all the dates were wrong.

The solution I eventually settled on was actually quite simple I explicitly set the default time zone to be UTC so that all dates are picked, stored and displayed in UTC. This is achieved by making this the first line in the first a ContextListener

TimeZone.setDefault(TimeZone.getTimeZone("UTC") );

Note that is has to be the first thing set since the default value for the time zone can be cached by the system. This setting will also affect everything else in the VM that uses the time zone so it can have unexpected consequences. If you need to pick or display dates in other time zones it’s simply a matter of setting the time zone attribute of the relevant element. Likewise when reading in dates from the database the time zone will need to be set explicitly but with MySQL you’d likely have had to so that anyway.

If you are having problem with the method call not happening early enough (seems to work fine with GlassFish 3.0.1) you can always set the system variable like this:

java -Duser.timezone=UTC

but personally I don’t like setting system properties this way, I find they confuser the people maintaining the system in production.

References