Wednesday, December 16, 2009

Retrieving Time Zone's DST information in Java

I have worked extensively with times. By time, I mean the software representation of time and the mapping of various concepts surrounding this tangible entity.

Handling of Time Zone, Daylight Saving Time (DST) is a pretty important use case in most softwares. All programming languages have libraries specifically designed to manipulate time easily. However, the implementation of these APIs isn't standardized and therefore developers have to go through a learning curve in order to use these APIs effectively and correctly. But the fact is that most of the developers take the concept for granted and are contend to directly use the libraries without learning the concepts properly.

Web is full of these resources and help can be found for learning the concepts and correctly utilizing the APIs in different languages.
There's one small use case in Java for which I couldn't find any assistance and that simply is: retrieving DST details for a particular Time Zone in Java.

The java.util.TimeZone does contain DST information, however it is not exposed in a direct manner in any of the TimeZone related classes. Internally, TimeZone calculates DST in SimpleTimeZone class (an implementation of TimeZone), which is accessed within TimeZone via ZoneInfo class' static methods.

Look here for the DST related private members of java.util.SimpleTimeZone.

Fortunately, these fields are visible through the toString() method of this class. Have a look at the source.

For convenience I'm providing a simple listing to extract out the DST information of a particular TimeZone:




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**
  * DST details for the time zone i.e. when DST is applied and when it ends.
  * @return
  */
public static String getDSTDetails(TimeZone timeZone) {

if (timeZone.getDSTSavings() > 0) {
/* Java's TimeZone related classes compute the start and end date of DST application but
    * do not expose it. The only way is to decipher the toString method which fortunately
    * prints enough information for us to deduce our required data.
    */
Pattern pattern = Pattern.compile("startMonth=(\\d+),startDay=(\\d+),.+endMonth=(\\d+),endDay=(\\d+),");
Matcher m = pattern.matcher(timeZone.toString());
if (m.find()) {
Calendar startCal = Calendar.getInstance();
Calendar endCal = Calendar.getInstance();

startCal.set(Calendar.MONTH, Integer.valueOf(m.group(1)));
startCal.set(Calendar.DAY_OF_MONTH, Integer.valueOf(m.group(2)));

endCal.set(Calendar.MONTH, Integer.valueOf(m.group(3)));
endCal.set(Calendar.DAY_OF_MONTH, Integer.valueOf(m.group(4)));

final SimpleDateFormat monthFormatter = new SimpleDateFormat("MMMM");

return new MessageFormat("Daylight savings starts at day {0} of {1}, ends at day {2} of {3}")
.format(new Serializable[] {
startCal.get(Calendar.DAY_OF_MONTH), monthFormatter.format(startCal.getTime()),
endCal.get(Calendar.DAY_OF_MONTH), monthFormatter.format(endCal.getTime())
}
);
}
}

return "NA";
}


Complete source code is also available as a Github gist.

Feel free to contact me for queries regarding time handling in Java (and on a side note, Teradata).

5 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Thanks for endorsing. An alternative to reading API documentation is to have a peek at the source code.

    ReplyDelete
  3. Hi Iqbal,
    I have seen one of your post on Teradata Developer exchange asking about an effective way to handle the Timezones offset in Teradata..

    http://forums.teradata.com/forum/database/daylight-saving-time-dst-and-time-zone#comment-12179

    I was wondering if you figured out any ways ..

    nice blog man.. most of this post went over my head as I am not a java person ..

    Thank you..

    ReplyDelete
  4. Thanks for the compliments Madhu. I already responded to your question on the Teradata forum before looking at your comment over here. Please let me know if you need further help in this regard.

    ReplyDelete
  5. This approach only works if 'mode' is taken into consideration. As the example is written, it only works for 'mode' = DOM_MODE (0-Day of Month). For other modes, the startDay and endDay values are NOT the day of the month and must be adjusted. See private method java.util.SimpleTimeZone.getTransition.

    ReplyDelete