views:

197

answers:

3

I'm working on a world clock web application, and I'd like to add a function to note how and when each location will next undergo a DST change.

I'm using the DateTime and DateTime::Timezone CPAN modules, which seem to provide every conceivable function apart from this one! DateTime::Timezone is an implementation of the tz/Olson database.

So far, I'm comparing local offset to UTC, both now and 24 hours ahead, which allows me to flag what the effect is but not exactly when it occurs.

My proof of concept calculates this every minute. I'm thinking the next step is either:

  • create a lookup table using a similar method for the next 365 days to identify affected days, then look at each hour within those days

  • somehow parse the DST rules in the DateTime::Timezone module.

Any ideas? I should note that my knowledge of Perl is pretty basic.


Edit:

Looks like another option might be to port to PHP and use DateTimeZone::getTransitions. This did return an array of all transitions, but PHP 5.3.0 just added optional timestamp_begin and timestamp_end paramaters to limit to a range.

+7  A: 

The undocumented attribute _rules of an DateTime::TimeZone object gives you an array of DateTime::TimeZone::OlsonDB::Rule objects. These encode the start and end of observances.

my $o = DateTime::TimeZone->new(name => 'Europe/Vienna')->_rules->[1];
say sprintf "%s summertime ends at %s on %s in %s each year", $o->name, $o->at, $o->on, $o->month;

I advise you to file a bug to request that this API is made public and documented, so that your code can rely on it and it is going to be supported by the DT maintainers properly.

daxim
Interesting! I'll certainly file the bug.
e100
I filed the bug, but I understand from the response that this is part of the inner workings and not intended to be exposed. I'll try to find out more and update here.
e100
See http://www.timeanddate.com/time/dst2010.html Some countries might change the time when DST is observed, announcing the change just a few weeks beforehand. Maximum accuracy can't be achieved with an expert system based solution (e.g. a database). But daxim's solution should be good for most cases.
jmz
Here's the bug report and response: https://rt.cpan.org/Public/Bug/Display.html?id=59405
e100
A: 

One of the return values from calling localtime in list context is a DST flag.

# find next DST change
$t = $^T - ($^T % 60);
$isdst = (localtime($t))[8];
for (; $t += 60; ) {
    if ($isdst != (localtime($t))[8]) {
        print "Next DST change is at ", scalar localtime($t), "\n";
        last;
    }
}

$ perl nextdst.pl
Next DST change is at Sun Nov  7 01:00:00 2010
mobrule
Odd loop; why not: `do { $t += 60 } while $isdst == (localtime($t))[8]; print ...`
ysth
This only works for the server's local time; I need to handle multiple locations. I guess I could use a similar method with each of my DateTime objects, but it seems rather a brute force method if DST changes are based on simple rules?
e100
A: 

You can use the tz database.
http://www.twinsun.com/tz/tz-link.htm

"The public-domain time zone database contains code and data that represent the history of local time for many representative locations around the globe. It is updated periodically to reflect changes made by political bodies to time zone boundaries, UTC offsets, and daylight-saving rules."

There is even a perl module for it. "DateTime::TimeZone contains a script parse_olson that compiles tz source into Perl modules. It is part of the Perl DateTime Project, which is freely available under both the GPL and the Perl Artistic License. DateTime::TimeZone also contains a script tests_from_zdump that generates test cases for each clock transition in the tz database."

As you have said, you are already using this module, but it sounds like you're not using all it's features. I'm not sure how much of the tz code is exposed via the DateTime::TimeZone module. In which case you might be better off calling it. There are a number of web services already using the tz database so it's well used.

You probably should write a perl or shell script to download the tz database source periodically in order to keep the rules up to date.

Matt H
This is just copy-and-paste which reiterates the notes in my question.
e100
The rules are in the tz source code. Have a look!
Matt H