Monty, James T wrote:
>Please explain this. I've always thought DateTime *does* handle leap
>seconds correctly.

DateTime `knows', falsely, that there will be no more leap seconds after
the last one that it knows of.  You can see this, for example, by asking
what is the UTC time N seconds after a given UTC time.  Using DateTime
0.4304, for example, I get these correct results:

$ perl -MDateTime -we '$dt=DateTime->new(year=>2008, month=>12, day=>30, 
time_zone=>"UTC");$dt->add(seconds=>86400);print $dt,"\n"'
2008-12-31T00:00:00
$ perl -MDateTime -we '$dt=DateTime->new(year=>2008, month=>12, day=>31, 
time_zone=>"UTC");$dt->add(seconds=>86400);print $dt,"\n"'
2008-12-31T23:59:60
$

but then some dubious results for future dates:

$ perl -MDateTime -we '$dt=DateTime->new(year=>2010, month=>12, day=>31, 
time_zone=>"UTC");$dt->add(seconds=>86400);print $dt,"\n"'
2011-01-01T00:00:00
$

This says that there will be no leap at the end of 2010.  That *might*
be correct, but the IERS hasn't decided yet.  Or consider a longer span:

$ perl -MDateTime -we '$dt=DateTime->new(year=>2008, month=>12, day=>31, 
time_zone=>"UTC");$dt->add(seconds=>86400*10000);print $dt,"\n"'
2036-05-17T23:59:59
$

Exactly one leap second in the next 27 years, eh?  That's definitely
wrong.  We can make estimates of how many leaps will be required over
such a time, and they come out a lot higher than 1.  But again, we can't
be sure of the exact number.

Previous versions of DateTime, of course, don't know about the leap
second at the end of 2008, and will give different answers to some of the
questions posed above.  DateTime's calculations change due to software
upgrades, and FSM help you if you have different versions installed on
cooperating machines.

When faced with these questions, about the *exact* number of seconds
between future UTC times, the only correct answer is "I don't know".
A module that offers strictly correct leap second handling would have
to die() in those cases.  As my Time::UTC does:

$ perl -MMath::BigRat 
-MTime::UTC=utc_instant_to_ymdhms,utc_ymdhms_to_instant,utc_to_tai,tai_to_utc 
-we 'printf "%04d-%02d-%02dT%02d:%02d:%02d\n", 
&utc_instant_to_ymdhms(tai_to_utc(&utc_to_tai(&utc_ymdhms_to_instant(map 
{Math::BigRat->new($_)} (2008,12,30,0,0,0)))+86400))'
2008-12-31T00:00:00
$ perl -MMath::BigRat 
-MTime::UTC=utc_instant_to_ymdhms,utc_ymdhms_to_instant,utc_to_tai,tai_to_utc 
-we 'printf "%04d-%02d-%02dT%02d:%02d:%02d\n", 
&utc_instant_to_ymdhms(tai_to_utc(&utc_to_tai(&utc_ymdhms_to_instant(map 
{Math::BigRat->new($_)} (2008,12,31,0,0,0)))+86400))'
2008-12-31T23:59:60
$ perl -MMath::BigRat 
-MTime::UTC=utc_instant_to_ymdhms,utc_ymdhms_to_instant,utc_to_tai,tai_to_utc 
-we 'printf "%04d-%02d-%02dT%02d:%02d:%02d\n", 
&utc_instant_to_ymdhms(tai_to_utc(&utc_to_tai(&utc_ymdhms_to_instant(map 
{Math::BigRat->new($_)} (2010,12,31,0,0,0)))+86400))'
day 19357 has no UTC definition yet at -e line 1
$ perl -MMath::BigRat 
-MTime::UTC=utc_instant_to_ymdhms,utc_ymdhms_to_instant,utc_to_tai,tai_to_utc 
-we 'printf "%04d-%02d-%02dT%02d:%02d:%02d\n", 
&utc_instant_to_ymdhms(tai_to_utc(&utc_to_tai(&utc_ymdhms_to_instant(map 
{Math::BigRat->new($_)} (2008,12,30,0,0,0)))+86400*10000))'
instant 2473286433 has no UTC definition yet at -e line 1
$

DateTime also goes wrong for times prior to 1972 (which is when the
current system of leap seconds started).  From 1961 onwards UTC was a
system of `rubber seconds', running at an anually-tweaked frequency offset
from TAI, with sub-second leaps (mostly of 0.1 s).  DateTime represents
neither of these aspects, instead implicitly assuming that there were
no leaps or frequency offsets in that era.

Prior to 1961 there was no UTC, and so DateTime is wrong to use that
term at all.  One could, hypothetically, retrospectively decide on
a set of leaps to use in this era, but no one has in fact determined
such a standard set.  Prior to 1958 there was no TAI, so there's no
base against which to determine leaps to retrospectively define UTC.
In all of these eras DateTime blithely pretends that there was UTC and
it just happened to never leap.

The time scale that DateTime effectively implements is composed of three
parts.  Prior to 1972 it is implicitly some unknown version of UT, i.e.,
an unspecified approximation to UT1.  It is a fully regular time scale,
in that all days have the same number of seconds.  From 1972 up to roughly
today, depending on how often you update your software, it is UTC with
leap seconds.  For future times it reverts to unspecified regular UT.

Oh, unless you're using the "floating" timezone.

So, anyway, most users don't need precise leap second handling.  Many,
presumably, do need (approximate) calculations on times in the future
and before 1972.  It is sensible for them that vague-regular-UT is
used in those eras.  But they'd be better served by a *consistent*
vague-regular-UT model.  No one is well served by the mixed model: it's
vague *ir*regular UT, not guaranteeing any of the useful things that
its component models do.  DateTime tries to be everything to everyone,
and suffers from the resulting contradictions.

(Yes, I'm a pedant.)

-zefram

Reply via email to