Thursday, March 24, 2011

Timezones and Servlets

When setting up a new servlet/database application, an often overlooked configuration item is the timezone, especially if dealing with a geographically distributed server installation (ie. Amazon AWS_

Database DATETIME Ambiguity
Without timezone consideration, the exact meaning of a DATETIME field in your MySQL database becomes ambiguous, as there is no timezone information embedded in that data-type. Consider that a DATETIME field is ultimately just recorded as a Unix timestamp of type LONG, which is just the number of seconds since the epoch. The epoch, of course, is midnight of January 1, 1970. But midnight where? The epoch changes depenending on which timezone you're in! This makes all your timestamp values dependent upon the system's current timezone, which could yield large differences if you have servers in different timezones.

Daylight Savings
Another consideration is the dreaded Daylight Savings. Aside from providing a moving target when trying to do translate timestamps from one timezone to another, it also provides an interesting wrinkle in that some DATETIMEs exist twice, while others do not exist at all. When we "spring forward", all the DATETIME values between 0200 and 0300 do not exist! If you try to declare a Java Date object, for example, you'll get an exception. Similarly, when we "fall back" then all the DATETIME values between 0100 and 0200 exist twice. This can cause double-counting on reports and sorting issues.

Coordinated Universal Time
Luckily a ready solution exists to these issues, which is to run all your servers in the "UTC" timezone, which is that of Coordinated Universal Time. UTC has two characteristics which make it ideal for server time:
  1. There are no Daylight Savings Time adjustments.
  2. It has an offset of 0000 from GMT, meaning we can calculate display time in any region simply by applying the applicable offset from GMT. By example, Pacific Standard Time (PST) is 8 hours behind GMT (GMT-0800) so it is also eight hours behind UTC (UTC-0800). In the summer, Pacific Daylight Savings Time (PDT) is seven hours behind, so we would use (UTC-0700).
Server Configuration
Setting your server's timezone is dependent upon the OS and distribution, but CentOS and most modern Linux flavours use the same pattern.
  1. Find the timezone you desire in /usr/share/zoneinfo
  2. Create a symlink from "/etc/localtime" to that timezone file
So, to set to UTC, we would use:
sudo rm /etc/localtime
sudo ln -s /usr/share/zoneinfo/UTC /etc/localtime

You can verify the change with the "date" command, which displays the date in the local format.
Thu Mar 24 20:40:17 UTC 2011

Tomcat Configuration
If you cannot change the timezone for the entire server, you can also change it for your specific Tomcat (or any Java application). Normally Java will use the default timezone of the server, but you can change this via the JAVA_OPTS variable. Just add this argument:
-Duser.timezone=UTC

Trust But Verify
As a developer, you likely have little control over the environment on which your code will eventually be run. Despite best efforts by you and your Ops team, mistakes do happen. So, it is a wise idea to verify your timezone during application initialization to avoid doing any processing while in an incorrect timezone.
TimeZone tz = TimeZone.getDefault();
if (!tz.equals(TimeZone.getTimeZone("UTC"))) {
throw new ServletException(
"Server TimeZone set to '"
+ tz.getDisplayName()
+ "' but should be 'UTC'."
+ " Add '-Duser.timezone=UTC' to Tomcat VM launch parameters.");
}

No comments:

Post a Comment