Skip Menu |

Preferred bug tracker

Please visit the preferred bug tracker to report your issue.

This queue is for tickets about the DateTime CPAN distribution.

Report information
The Basics
Id: 71275
Status: resolved
Priority: 0/
Queue: DateTime

People
Owner: Nobody in particular
Requestors: zefram [...] fysh.org
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: (no value)



Subject: local_rdn_values at leap seconds
Date: Tue, 27 Sep 2011 14:01:18 +0100
To: bug-DateTime [...] rt.cpan.org
From: Zefram <zefram [...] fysh.org>
(This is what I really wanted to investigate that led to me discovering the preceding two bugs about timezones and leap seconds.) For a time at a leap second, the local_rd_values that DateTime supplies are problematic: they're generated inconsistently, and in the general case result in ambiguity. For reference, here's what the related utc_rd_values does: $ perl -MDateTime -lwe '$dt=DateTime->new(year=>2008,month=>12,day=>31,hour=>23,minute=>59,second=>60, time_zone=>"UTC"); print $dt; print join",",$dt->utc_rd_values' 2008-12-31T23:59:60 733407,86400,0 It returns a seconds-of-day value of 86400, which of course can't occur in a normal day. This uniquely identifies the leap second, and puts it in its proper numerical place relative to all the other seconds of the day. But that can only work when the leap second occurs right at the end of the day, which it does in UTC but in the general case doesn't in a timezone. Suppose we have a timezone offset of an hour: $ perl -MDateTime -lwe '$dt=DateTime->new(year=>2008,month=>12,day=>31,hour=>23,minute=>59,second=>60, time_zone=>"UTC"); $dt->set_time_zone("+01:00"); print $dt; print join",",$dt->local_rd_values' 2009-01-01T00:59:60 733408,3600,0 $ perl -MDateTime -lwe '$dt=DateTime->new(year=>2009,month=>1,day=>1,hour=>0,minute=>0,second=>0, time_zone=>"UTC"); $dt->set_time_zone("+01:00"); print $dt; print join",",$dt->local_rd_values' 2009-01-01T01:00:00 733408,3600,0 Stringification shows the correct broken-down time of 00:59:60. The local_rd_values show the correct day, and 3600 seconds into that day, which is understandable since the preceding second (00:59:59) was actually 3559 seconds into the day. However, 3600 is the same seconds-of-day value that one would normally expect for the time 01:00:00, and indeed the following second does show the same seconds-of-day value despite being a different time. So the local_rd_values result is ambiguous. It's also calculated inconsistently. For a timezone offset of zero I can get two different results, depending on whether the timezone is_utc: $ perl -MDateTime -lwe '$dt=DateTime->new(year=>2008,month=>12,day=>31,hour=>23,minute=>59,second=>60, time_zone=>"UTC"); $dt->set_time_zone("UTC"); print $dt; print join",",$dt->local_rd_values' 2008-12-31T23:59:60 733407,86400,0 $ perl -MDateTime::TimeZone::SystemV -MDateTime -lwe '$dt=DateTime->new(year=>2008,month=>12,day=>31,hour=>23,minute=>59,second=>60, time_zone=>"UTC"); $dt->set_time_zone(DateTime::TimeZone::SystemV->new("UTC0")); print $dt; print join",",$dt->local_rd_values' 2009-01-01T23:59:60 733408,0,0 For the is_utc zone, local_rd_values returns the correct day and the same distinctive (but irregular) seconds-since-day value as utc_rd_values. For the non-is_utc zone, which otherwise behaves identically, local_rd_values returns (as for the non-zero offsets) a regular-looking seconds-of-day value that appears to identify the second following the leap second. In this case that also involves showing the wrong day. The Europe/London zone, which is not generally equivalent to UTC but happens to have a zero offset at that time, also produces what looks like the first second of the next day. DateTime doesn't document what utc_rd_values and local_rd_values are meant to do around a leap second. It does say they're meant for other modules to be able to extract the time represented by the object. To have local_rd_values return an apparently-regular value for the leap second, ambiguous with the following second, defeats this purpose, because its value doesn't fully identify the local time represented by the object. Since providing seconds-of-day = 86400 only works at the very end of the day, that's not a solution either. For local_rd_values to be fully useful, it's going to need some other behaviour. For the purposes of timezones, in the modern era timezones are all UTC-compatible by virtue of using only offsets of integral minutes, so usually the number of seconds into the minute doesn't matter. Timezones therefore usually want to treat a leap second like the preceding second (xx:xx:59). It would be convenient if leap seconds were indicated by having seconds-of-day the same as it was for the preceding second and letting the nanoseconds-of-second value exceed 10^9. This trick has been proposed for struct timeval/timespec in some situations, and it doesn't run into 32-bit trouble. -zefram