Friday, July 20, 2007

Java Dates, Calendars and TimeZones

We all know Java date handling is a pain. I'm sure most Java developers give as little thought as possible to dates, less to calendars, and none to time zones. We use new java.util.Date() as much as possible and avoid java.util.Calendar like the plague. This works out, more or less, until you need to account for time zones. Java dates don't include any time zone related methods so it's easy to ignore them, we forget that dates really have a time zone of Greenwich Mean Time (GMT).

The thing to remember is that a Java date is a very simple object . If you remove the deprecated constructors and methods there is not much left besides equals(), hashCode() and getTime(). A date is really just a wrapper around a Java long integer value and that long integer is the number of milliseconds since January 1, 1970, 00:00:00 GMT. We forget about the GMT business because whenever we print a date it looks like this -

Sun Jul 15 10:00:00 CDT 2007

It is easy to forget that the output of toString() is the value of the date in a localized format for display and not the real value. The same date printed in two different time zones would look different even though the actual long integer value is the same. Here is an example that may help -

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;

public class CalendarTimeZoneTest {
private static String getCalendarDate(Calendar cal) {
return (cal.get(Calendar.MONTH) + 1) + "/" +
cal.get(Calendar.DAY_OF_MONTH) + "/" +
cal.get(Calendar.YEAR) + " " +
cal.get(Calendar.HOUR_OF_DAY) + ":" +
cal.get(Calendar.MINUTE) + ":" +
cal.get(Calendar.SECOND);
}

private static Calendar getCalendarForTimeZone(TimeZone tz) {
Calendar cal = new GregorianCalendar(tz);
cal.clear();
cal.set(Calendar.HOUR_OF_DAY, 10);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MONTH, 6);
cal.set(Calendar.YEAR, 2007);
cal.set(Calendar.DAY_OF_MONTH, 15);
return cal;
}

private static void showDate(Calendar Cal) {
System.out.println(" Time zone : " +
Cal.getTimeZone().getDisplayName());
System.out.println(" Milliseconds : " +
Cal.getTimeInMillis());
System.out.println(" Calendar Date: " +
getCalendarDate(Cal));
System.out.println(" Local Date : " +
new Date(Cal.getTimeInMillis()));
System.out.println();
}

public static void main(String[] args) {
Calendar localCal =
getCalendarForTimeZone(TimeZone.getTimeZone("America/Chicago"));
Calendar japanCal =
getCalendarForTimeZone(TimeZone.getTimeZone("Japan"));
System.out.println("Same date/time in different time zones");
showDate(localCal);
showDate(japanCal);
System.out.println();

japanCal = new GregorianCalendar(TimeZone.getTimeZone("Japan"));
japanCal.setTimeInMillis(localCal.getTimeInMillis());
System.out.println("Same milliseconds in different time zones");
showDate(localCal);
showDate(japanCal);
}

First the example creates two calendars with the same date and time for two different time zones. This results in two dates with different millisecond values. Next, the example creates two calendars with the same milliseconds in two different time zones. The output looks like -

Same date/time in different time zones
Time zone : Central Standard Time
Milliseconds : 1184511600000
Calendar Date: 7/15/2007 10:0:0
Local Date : Sun Jul 15 10:00:00 CDT 2007

Time zone : Japan Standard Time
Milliseconds : 1184461200000
Calendar Date: 7/15/2007 10:0:0
Local Date : Sat Jul 14 20:00:00 CDT 2007


Same milliseconds in different time zones
Time zone : Central Standard Time
Milliseconds : 1184511600000
Calendar Date: 7/15/2007 10:0:0
Local Date : Sun Jul 15 10:00:00 CDT 2007

Time zone : Japan Standard Time
Milliseconds : 1184511600000
Calendar Date: 7/16/2007 0:0:0
Local Date : Sun Jul 15 10:00:00 CDT 2007

What I hope the example demonstrates is that the same Java date, i.e. millisecond value, has different meanings in different time zones. If you want the same date and time in different time zones you must take the offset between time zones into account. The easiest way to do this using the standard Java libraries is to create a date from its parts, year, month, day, etc., using a Java calendar object.

2 comments:

Joshua Smith said...

Thanks a lot for writing about useful review. It is required to understand that android apps development could help in your business by installing customized software apps. Also you may turn your attention on outsource asp.Net development.

camobel said...

It won't work in actual fact, that's exactly what I suppose.