Friday, April 8, 2011

Find DST transition timestamp with java.util.TimeZone

Is it possible to get the previous and next DST transition timestamp with the Java Calendar/Date/TimeZone API?
With Joda-Time I can write:

DateMidnight today = new DateMidnight(2009, 2, 24);
DateTimeZone zone = today.getZone();

DateTime previousTransition =
    new DateTime(zone.previousTransition(today.getMillis()));
// 2008-10-26T02:59:59.999+02:00 for Europe/Berlin
System.out.println(previousTransition);

DateTime nextTransition =
    new DateTime(zone.nextTransition(today.getMillis()));
// 2009-03-29T03:00:00.000+02:00 for Europe/Berlin
System.out.println(nextTransition);

Is there way to do this with the standard Java APIs?

From stackoverflow
  • There's no such functionality in java Date/Calendar/TimeZone API

  • The best I came up with, when I needed such functionality, is to use a Calendar and iterate through entire year, in specified time zone, and ask if each hour of each day is it the begging or ending of DST.

    You have to do it like that because on Sun's JVM, the implementation of TimeZone (sun.util.calendar.ZoneInfo) holds data about time zone transitions in some kind of "compiled" form.

    Code goes something like this:

    public class Dst {
        Date start;
        Date end;
    
        public static Dst calculate(TimeZone tz, int year) {
            final Calendar c = Calendar.getInstance(tz);
            c.setLenient(false);
            c.set(year, Calendar.JANUARY, 1, 1, 0, 0);
            c.set(Calendar.MILLISECOND, 0);
    
            if (tz.getDSTSavings() == 0) {
                return null;
            }
    
            Dst dst = new Dst();
    
            boolean flag = false;
    
            do {
                Date date = c.getTime();
                boolean daylight = tz.inDaylightTime(date);
    
                if (daylight && !flag) {
                    flag = true;
                    dst.start = date;
                }
                else if (!daylight && flag) {
                    flag = false;
                    dst.end = date;
                }
    
                c.add(Calendar.HOUR_OF_DAY, 1);
            }
            while (c.get(Calendar.YEAR) == year);
    
            return dst;
        }
    }
    

    Of course, it would make sense to cache/memoize the result of these calculations etc.

    Hope this helps.

    JodaStephen : This approach is risky as some time zones have had double summer time, where they go from standard to summer, then from summer to double summer (typically +2 hours). The code above wouldn't catch those additional transitions.
  • Yes, there is an indirect way to retrieve this from Java API. Check this out and let me know if this works for the problem:

    http://monisiqbal.blogspot.com/2009/12/retrieving-time-zones-dst-information.html

    This should give you the required info for the current year, you can easily do the same for previous years if you want to.

    Ludwig Wensauer : does not work with the timezone 'Europe/Berlin'. `System.out.println(TimeZone.getTimeZone("Europe/Berlin"))` prints *...startMonth=2,startDay=-1,...endMonth=9,endDay=-1..."* And there is just the date, **no time** -> down vote.

0 comments:

Post a Comment