Eugene van der pijll wrote:
>Jim Monty schreef:
>> I want to iterate the time zones of the world to generate a report of
>> all days that aren't exactly 24 hours. I want to handle
>> America/Caracas and America/Sao_Paulo correctly. You mentioned
>> 2007-12-09 was 24.5 hours long in Venezuela. This is precisely the
>> kind of outlier I'm after.
>
> If you want to handle the Sao Paulo situation correctly, measure the
> intervals between two middays (12:00), instead of between midnights (0:00).
>
> It should show the same non-24 hour days, except when there are two DST
> changes in one day. Which is unlikely, but not impossible, given that
> DST is defined by politicians.

It seems there's no one-size-fits-all workaround for all time zones in all 
years.

Here's my first shot at a script. It combines Zefram's suggestion to use 
$dt->epoch() and Eugene's recommendation to measure the intervals at noon 
instead of at midnight. Next, I'd like to refactor it using...um...I'm not 
sure, but something other than $dt->epoch().

    #!perl
    
    use strict;
    use warnings;
    
    use DateTime;
    
    @ARGV or die "Usage: perl $0 <year> ...\n";
    
    for my $year (@ARGV) {
        for my $time_zone (DateTime::TimeZone->all_names()) {
            my $today = DateTime->from_day_of_year(
                year        => $year,
                day_of_year => 1,
                hour        => 12,
                time_zone   => $time_zone,
            );
    
            (my $yesterday = $today->clone())->subtract( days => 1 );
            my $hours = ($today->epoch() - $yesterday->epoch()) / 3_600;
            my $year_today = $today->year();
    
            while ($year_today == $year) {
                (my $tomorrow = $today->clone())->add( days => 1 );
    
                my $date = $today->date();
    
                if ($hours != 23 && $hours != 24 && $hours != 25) {
                    printf("%-10s  %-4s  %s\n", $date, $hours, $time_zone);
                }
    
                $hours = ($tomorrow->epoch() - $today->epoch()) / 3_600;
                $today = $tomorrow;
                $year_today = $today->year();
            }
        }
    }
    
    exit 0;
    
    __END__


    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
    
    C:\>

It's easy enough to find stranger and even more problematic dates.

    C:\>perl oddhours.pl 1961
    1961-01-01  23.7458333333333  Africa/Dar_es_Salaam
    1961-08-10  23.5  Asia/Seoul
    
    C:\>perl oddhours.pl 1967
    Invalid local time for date in time zone: Africa/Casablanca
    
    C:\>

Since this is my first effort to do something quasi-useful with DateTime using 
DateTime math, all feedback, criticisms and suggestions are most welcome.

Jim Monty

Reply via email to