[EMAIL PROTECTED] wrote:
>    C:\>perl oddhours.pl 2007
>    2007-12-09  24.5  America/Caracas
>    2007-03-11  22    America/Indiana/Winamac
>    2007-03-25  24.5  Australia/Lord_Howe
>    2007-10-28  23.5  Australia/Lord_Howe

Interesting, Australia/Lord_Howe does a half-hour DST shift every year.

>    1961-01-01  23.7458333333333  Africa/Dar_es_Salaam

That's the switch from an unaligned +02:44:45 to the regular +03:00.
Curiously, it went to +02:44:45 *from* +03:00 earlier, in 1948, and
before that (until 1931) it had used +02:37:08.  Strong odour of politics.

>    C:\>perl oddhours.pl 1967
>    Invalid local time for date in time zone: Africa/Casablanca

Wow, someone *does* switch at noon.  Or did, once.  A quick look at the
tzdata files shows a handful of other noon switches, all one-offs.

I think you're going to have to give up the idea of using a fixed local
time each day as your reference point.  You need a function that finds
the earliest point that lies within a given calendar date in local time,
which will usually (but not always) be labelled 00:00.  It's probably
safer to work in UTC and convert to local, rather than work with local
time-of-day directly, to avoid trouble with ambiguous times of day
(there might be two instances of local 00:00 in one day).

This is still assuming that the extent of each local calendar day
is contiguous.  If the clocks go back an hour at 00:30 local time,
it would break your model.  The Alaskan zones stretch the model to
the limit, having in 1867 a jump back by 24 hours at 24:00 local time,
yielding a 48-hour day.  (Subjectively it was treated as two consecutive
Fridays, which would have had the same calendar date were it not for the
simultaneous switch from the Julian calendar to the Gregorian calendar.)
There are also some Pacific islands that have jumped across the IDL in
the other direction, skipping a calendar date altogether.

Anyway, have a go with this function:

sub day_start($$$$) {
        my($zone, $y, $m, $d) = @_;
        my $p = DateTime->new(time_zone=>"UTC", year=>$y, month=>$m, day=>$d, 
hour=>12);
        (my $rd) = $p->utc_rd_values;
        while(do { (my $l = $p->clone)->set_time_zone($zone); 
[$l->local_rd_values]->[0] } >= $rd) {
                $p->subtract(hours=>1);
        }
        while(do { (my $l = $p->clone)->set_time_zone($zone); 
[$l->local_rd_values]->[0] } < $rd) {
                $p->add(hours=>1);
        }
        my $q;
        while(1) {
                ($q = $p->clone)->subtract(minutes=>1);
                last if do { (my $l = $q->clone)->set_time_zone($zone); 
[$l->local_rd_values]->[0] } < $rd;
                $p = $q;
        }
        while(1) {
                ($q = $p->clone)->subtract(seconds=>1);
                last if do { (my $l = $q->clone)->set_time_zone($zone); 
[$l->local_rd_values]->[0] } < $rd;
                $p = $q;
        }
        return $p;
}

-zefram

Reply via email to