Zefram schreef:
> It ought to be possible to do the interval calculation using
> DateTime::Duration instead of ->epoch, but the behaviour of DT::D is
> unreasonably confusing and I couldn't get it to work.  (Strangely, I got
> a version that worked fine for America/New_York, where all the days are
> integer numbers of hours, but lost the fractional hour of 2007-12-09 in
> America/Caracas, which was 24.5 hours long.)

DateTime cannot handle fractional leap hours.

See the source code of subtract_datetime(), section "This is a gross
hack", where the length of the leap hour is hardcoded in the lines

    $bigger_min -= 60
    $bigger_min += 60

This should probably be changed, but datetime math is scary.

As a workaround, convert the time to UTC. (This does not work in all
cases, but for this purpose, it does.

use DateTime;

for my $doy (340..345) {

    # The default time is 00:00:00
    my $day = DateTime->from_day_of_year(
                                year => 2007, day_of_year => $doy,
                                time_zone => 'America/Caracas') or die;

    # To find the end of the day, add 1 day to get 00:00:00 tomorrow
    my $end_of_day = $day->clone->add( days => 1 );

    # Workaround for Venezuela.
    $day->set_time_zone('UTC');
    $end_of_day->set_time_zone('UTC');

    # Standard subtraction would result in a duration of 1 day, so we
    # use delta_ms() which results in a duration without the "days"
    # component. It is expressed entirely in minutes, which can be
    # converted to hours.
    my $hours = $end_of_day->delta_ms($day)->delta_minutes / 60;

    print $day, " has $hours hours.\n";
}


Eugene

Reply via email to