Zhu Wu's Blog

The world is a fine place and worth fighting for.

Handle Time Zone in Java

It is important to process and present date and time correctly when building an application, especially when your application is going to be used by users from more than one time zones. This article will give you more insights on how to deal time zone in a correct way in Java.

Before we dig into time zone, we need to understand timestamp in Java. Timestamp is defined as number of milliseconds since 00:00:00 Thursday, 1 January 1970 UTC (this time is also known as Epoch time). From the definition, it is easy to understand that a timestamp is not related to any time zone. For example, time stamp of 29 Feb 2016, 12:34:56 (UTC+8) is 1456720496000, which is identical to time stamp of 29 Feb 2016, 05:34:56 (UTC+1).

Since the same time in different time zone has the same timestamp, the timestamp is a good reference point for us when dealing date and time in Java. The only thing we need to cater is how to translate a time zone based time into timestamp and how to present the time stamp in human readable format according to target time zone. Java provides us the following classes to do the manipulations:

Class Functionality Set Time Zone
Date Wrapper of timestamp. Not applicable.
SimpleDateFormat 1) Parse a string to a Date object according to certain pattern.
2) Display a Date object according to certain pattern.
Supply time zone when calling setTimeZone method.
Calendar Maintain and manipulate a set of calendar fields such as year, month, day of month, hour, minute, second, millisecond, etc. 1) Supply time zone when calling getInstance method.
2) Supply time zone when calling setTimezone method.

Maybe the target users of your application come from one time zone only, but you still need to take good care of time zone because time zone can be changed by authority. For example, here is an example program to calculate difference in seconds between two times (please note line 8 to set time zone for the SimpleDateFormat object):

import java.text.SimpleDateFormat;
import java.text.ParseException;
import java.util.Date;
import java.util.TimeZone;
public class Main{
  public static void main(String[] args) throws ParseException {
    SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    sf.setTimeZone(TimeZone.getTimeZone("Asia/Singapore"));
    String time1 = "1981-12-31 23:59:59";
    String time2 = "1982-01-01 00:30:00";
    Date date1 = sf.parse(time1);
    Date date2 = sf.parse(time2);
    long second1 = date1.getTime() /1000;
    long second2 = date2.getTime() /1000;
    System.out.println(second2 - second1);
  }
}

You may think the program should output 30 * 60 + 1 = 1801 at first glance since it looks like these two times have 30 minutes and 1 second in difference. However, the program outputs 1 instead of 1801. Why? Referring to http://www.timeanddate.com/time/change/singapore/singapore?year=1982, we know that Singapore changed its time zone from UTC+7:30 to UTC+8 on 1 January 1982, and clocks were turned forward 30 minutes to Friday, 1 January 1982, 00:30:00 when local time was about to read 1 January 1982, 00:00:00. Thus, 31 December 1981, 23:59:59 and 1 Janurary 1982, 00:30:00 have only only 1 second in difference!

Thus, as a best practice, we should always store timestamp instead of string with certain date format when persistence is required, and display it out according to required time zone. Always be careful when you parse a date string.