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