Peter J. Acklam schreef:
> And you say that Perl is "usually" using UTC.  Then please show me
> some examples of Perl giving the following, which would be correct
> for an UTC clock.  Actually, just one example would be nice.
> 
>     $ perl -wle 'print scalar gmtime $_ for 78796799 .. 78796801'
>     Fri Jun 30 23:59:59 1972
>     Fri Jun 30 23:59:60 1972
>     Sat Jul  1 00:00:00 1972

This is a correct implementation of UTC time; and as you say, this is
rarely implemented.

> The second before 1972-07-01 00:00:00 UTC was a leap second (the
> first leap second after 1970).  Every version of Perl I have
> available gives me
> 
>     $ perl -wle 'print scalar gmtime $_ for 78796799 .. 78796801'
>     Fri Jun 30 23:59:59 1972
>     Sat Jul  1 00:00:00 1972
>     Sat Jul  1 00:00:01 1972
> 
> happily ignoring the leap second.

This looks like TAI, but it isn't. Perl uses UTC, but skips the leap
seconds. You can see this in local times. For example, MET is defined
as UTC+0100, not as TAI+0100. In perl:

    $ perl -wle 'print scalar localtime $_ for 78796799 .. 78796801'
    Sat Jul  1 00:59:59 1972
    Sat Jul  1 01:00:00 1972
    Sat Jul  1 01:00:01 1972

If Perl (or the underlying library functions) used TAI, it should have
printed something like

    $ perl -wle 'print scalar localtime $_ for 78796799 .. 78796801'
    Sat Jul  1 01:00:09 1972
    Sat Jul  1 01:00:10 1972
    Sat Jul  1 01:00:11 1972

(because UTC=TAI-10s, TAI and MET differed 1 hour and 10 seconds in
1972)

And if Perl used real UTC, the output would have been

    $ perl -wle 'print scalar localtime $_ for 78796799 .. 78796801'
    Sat Jul  1 00:59:59 1972
    Sat Jul  1 00:59:60 1972
    Sat Jul  1 01:00:00 1972


If you want to have a libtai-like epoch, which counts the leap seconds,
use the DateTime::Format::Epoch module:

    use DateTime::Format::Epoch;

    my $dt = DateTime->new( year => 1970, month => 1, day => 1 );

    my $tai = DateTime::Format::Epoch->new(epoch=>$dt, skip_leap_seconds=>0);
    my $utc = DateTime::Format::Epoch->new(epoch=>$dt, skip_leap_seconds=>1);

    for (78796799 .. 78796803) {
        print DateTime->from_epoch(epoch => $_)->datetime, "   ",
              $tai->parse_datetime($_)->datetime, "   ",
              $utc->parse_datetime($_)->datetime, "\n";
    }

1972-06-30T23:59:59   1972-06-30T23:59:58   1972-06-30T23:59:59
1972-07-01T00:00:00   1972-06-30T23:59:59   1972-07-01T00:00:00
1972-07-01T00:00:01   1972-06-30T23:59:60   1972-07-01T00:00:01
1972-07-01T00:00:02   1972-07-01T00:00:00   1972-07-01T00:00:02
1972-07-01T00:00:03   1972-07-01T00:00:01   1972-07-01T00:00:03

DateTime objects are of course in UTC. Perhaps a DateTime::Format::TAI
is needed?

Eugene

P.S. It looks like there was a leap second before 1972-06-30. Is that
correct?

Reply via email to