Re: How to Compute Hours In a Day?
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.74583 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
Re: How to Compute Hours In a Day?
[EMAIL PROTECTED] schreef: 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(). I think the script in my first mail comes close; I'd start there. It's easy enough to find stranger and even more problematic dates. C:\perl oddhours.pl 1961 1961-01-01 23.74583 Africa/Dar_es_Salaam In the 19th century, there were no time standards, and each city used its own local time. At some point, times within a country were standardized; often to an integer offset with GMT, sometimes first to the local time of the capital. Check out 1883, when the U.S. moved from local time to standard time zones. That results in a lot of strange day lengths. Apparently, Tanganyika moved to standard time in 1961. C:\perl oddhours.pl 1967 Invalid local time for date in time zone: Africa/Casablanca And so there are time zones that change at noon... Those wacky politicians... In Morocco in 1967, and only in that year, DST started on June 3, 12:00. Eugene
Re: How to Compute Hours In a Day?
[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.74583 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