The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Time::UTC - manipulation of UTC in terms of TAI

SYNOPSIS

        use Time::UTC qw(
                utc_start_segment
                foreach_utc_segment_when_complete
                utc_start_tai_instant utc_start_utc_day
                utc_segment_of_tai_instant utc_segment_of_utc_day
        );

        $seg = utc_start_segment;
        foreach_utc_segment_when_complete { ... $_[0] ... };

        $instant = utc_start_tai_instant;
        $day = utc_start_utc_day;

        $seg = utc_segment_of_tai_instant($instant);
        $seg = utc_segment_of_utc_day($day);

        use Time::UTC qw(
                utc_day_leap_seconds utc_day_seconds
                utc_check_instant
        );

        $secs = utc_day_leap_seconds($day);
        $secs = utc_day_seconds($day);
        utc_check_instant($day, $secs);

        use Time::UTC qw(tai_to_utc utc_to_tai);

        ($day, $secs) = tai_to_utc($instant);
        $instant = utc_to_tai($day, $secs);

        use Time::UTC qw(
                utc_secs_to_hms utc_hms_to_secs
                utc_day_to_ymd utc_ymd_to_day
                utc_instant_to_ymdhms utc_ymdhms_to_instant
        );

        ($hr, $mi, $sc) = utc_secs_to_hms($secs);
        $secs = utc_hms_to_secs($hr, $mi, $sc);

        ($yr, $mo, $dy) = utc_day_to_ymd($day);
        $day = utc_ymd_to_day($yr, $mo, $dy);

        ($yr, $mo, $dy, $hr, $mi, $sc) =
                utc_instant_to_ymdhms($day, $secs);
        ($day, $secs) = utc_ymdhms_to_instant(
                                $yr, $mo, $dy, $hr, $mi, $sc);

DESCRIPTION

This module encapsulates knowledge about the structure of the UTC time scale, including the leap seconds of the current incarnation. This information is useful in manipulating times stored in a UTC-based format, or in converting between UTC and TAI (the underlying atomic time scale). This is a low-level module, intended for use by other modules that need to know about UTC. This module aims to be comprehensive and rigorous.

ORIGIN OF UTC

Until the middle of the twentieth century, the passage of time was measured primarily against the astronomical motions of the Earth and other bodies. These motions are very regular, and indeed were the most temporally regular phenomena available to pre-industrial society. After the invention of the caesium-based atomic clock, a gradual transition from astronomic to atomic timekeeping began. The hyperfine structure of caesium is more regular than the Earth's motion, and so makes a better time standard. Unfortunately, this means that during the transition phase there are two disagreeing time standards in use, and we must jump through hoops to accommodate both. UTC is one of these hoops.

Solar timekeeping

Each revolution of the Earth relative to the Sun (i.e., each day) has traditionally been divided into units of hours, minutes, and seconds. These are defined such that there are exactly 86400 seconds in a day. Since these units are measuring the rotation of the Earth, rather than the passage of time per se, it makes more sense to view these as measures of angle than of time. Thus, the hour refers to a rotation of exactly 15 degrees, regardless of how much time that rotation takes, and so on.

Because the Earth's rotation is non-uniform, each day is a slightly different length, and so the duration of the second, as defined above, also varies over time. This is not good in a time standard. In order to make the time as stable as possible, the non-uniformities of the Earth's rotation need to be accounted for. The use of mean solar time rather than apparent solar time smooths out variation in the apparent daily motion of the Sun over the course of the year. The mean solar time at Greenwich is known as Universal Time, and specifically as UT0. UT1 and UT2 are further smoothed versions of Universal Time.

But however smoothed these scales get, they remain fundamentally measures of angle rather than time. They are not uniform over time.

Atomic timekeeping

It has been long recognised that the Earth's rotation is non-uniform, and so that the scales based on the Earth's rotation are not stable measures of time. Scientists have therefore defined units of time that are unrelated to the Earth's current motions. Confusingly, the unit so defined is called the "second", and is arranged to have a duration similar to that of the traditional angle-based second, despite being fundamentally different in intent.

The second in this sense was originally defined as 1/86400 of the mean duration of a solar day. In 1956 the second was redefined in terms of the length of the tropical year 1900. This definition was superseded in 1967 by a definition based on the hyperfine transition of caesium. That definition was refined in 1997, and further refinements may happen in the future.

The important aspects of atomic timekeeping, for our purposes, are that it is more stable than the Earth's spin; it is independent of the Earth's current spin; and it confusingly uses much of the same terminology as measurement of the Earth's spin.

TAI

Time started to be measured internationally using atomic clocks starting (nominally) at the beginning of 1958. A time scale was introduced, known as International Atomic Time or TAI. TAI is strictly a measure of time as determined by atomic clocks, and is entirely indepenent of the Earth's daily revolutions. However, it uses the terminology and superficial appearance of the time scales that went before it, which is to say the angle scales. Thus a point on the TAI scale is conventionally referred to by specifying a date and a time of day, the latter composed of hours, minutes, and seconds.

Like the pure measures of rotation, TAI has exactly 86400 seconds per day. Completely unlike those measures, TAI's seconds are, as far as possible, of identical duration, the duration with which the second was defined in 1967. TAI was initially synchronised with Universal Time, so that TAI and UT1 describe the same instant as 1958-01-01T00:00:00.0. TAI now runs independently of UT1, and at the time of writing (early 2005) TAI is about 32.5 seconds ahead of UT1.

UTC

Over the long term, the world is switching from basing civil time on UT1 (i.e., the revolution of the Earth) to basing civil time on TAI (i.e., atomic clocks). In the short term, however, a clean switch is not such a popular idea. There is a demand for a hybrid system which is based on atomic clocks but which also maintains synchronisation with the Earth's spin. UTC is that system.

UTC is defined in terms of TAI, and is in that sense an atomic time standard. However, the relation between UTC and TAI is determined only a few months in advance. The relation changes over time, so that UTC remains an approximation of UT1.

There have been two forms of UTC so far. The initial form, from the start of 1961, used a second of a different length from the standard second, but a fixed multiple of it. (Confusingly, this is a third type of "second".) UTC was offset from TAI, with the offset continuously changing due to the differing lengths of the second. The length of the UTC second was occasionally changed, and there were also occasional jumps in UTC time, both forward and backward, most commonly by 0.1 s at a time. Jumps were achieved by making a UTC day have a length other than 86400 UTC seconds.

Since 1972, the form of UTC has been less complicated. In this era the UTC second is identical in duration to the TAI second, and the difference between UTC and TAI is always an integral number of seconds. There are occasional jumps of UTC time by one second at a time. So far there have only been backward jumps (by having an 86401 s UTC day), but forward jumps are also theoretically possible.

Notice that the new form of UTC is more similar to TAI than the old form was. This appears to be part of the gradual switch from solar time to atomic time. It has been proposed that in the near future the system of discontinuities in UTC will terminate, resulting in a purely atomic time scale.

STRUCTURE OF UTC

UTC is a time scale derived from TAI. UTC divides time up into days, and each day into seconds. Most UTC days are exactly 86400 UTC seconds long, but they can be up to a second shorter or longer. The UTC second is in general slightly different from the TAI second; it stays stable most of the time, occasionally undergoing an instantaneous change. Since 1972 the UTC second has been equal to the TAI second, and it will remain so in the future.

The details of the day lengths, and until 1972 the length of the UTC second, are published by the International Earth Rotation and Reference Systems Service (IERS). They are announced only a few months in advance, so it is not possible to convert between TAI and UTC for times more than a few months ahead.

UTC is not defined for dates prior to 1961.

FUNCTIONS

Because UTC is defined purely in terms of TAI, these interfaces make frequent use of the TAI epoch, 1958-01-01T00:00:00.0. Instants on the TAI scale are identified by a scalar number of TAI seconds since the TAI epoch; this is a perfectly linear scale with no discontinuities. The TAI seconds count can be trivially split into the conventional units of days, hours, minutes, and seconds for display (TAI days contain exactly 86400 TAI seconds each).

Because UTC days have differing lengths, instants on the UTC scale are identified by the combination of an integral number of days since the TAI epoch and a number of UTC seconds since midnight within the day. In some interfaces the day number is used alone. The conversion of the number of seconds within a day into hours, minutes, and seconds for display is idiosyncratic; the function utc_secs_to_hms handles this.

All numbers in this API are Math::BigRat objects. All numeric function arguments must be Math::BigRats, and all numeric values returned are likewise Math::BigRats.

Description of UTC

This module contains a machine-manipulable description of the relation between UTC and TAI. Most users of this module do not need to examine this directly, and will be better served by the higher-level functions described later. However, users with unusual requirements have access to the description if necessary. The functions in this section deal with this.

The internal description is composed of Time::UTC::Segment objects. Each segment object describes a period of time over which the relation between UTC and TAI is stable. See Time::UTC::Segment for details of how to use these objects. More segments can appear during the course of a program's execution: updated UTC data is automatically downloaded as required.

utc_start_segment

Returns the first segment of the UTC description. The later segments can be accessed from the first one. This function is intended for programs that will walk through the entire description.

foreach_utc_segment_when_complete(WHAT)
foreach_utc_segment_when_complete BLOCK

WHAT must be a reference to a function which takes one argument; it may be specified as a bare BLOCK in the function call. The function is called for each segment of the UTC description in turn, passing the segment as an argument to the function. This call takes place, for each segment, when it is complete, as described in Time::UTC::Segment. The function is immediately called for already-complete segments.

To do this for only one segment, see the when_complete method on Time::UTC::Segment.

utc_start_tai_instant

Identifies the instant at which the UTC service started. This instant was the start of the first UTC day.

utc_start_utc_day

Identifies the first day of UTC service.

utc_segment_of_tai_instant(INSTANT)

Returns the segment of the UTC description that pertains to the specified TAI instant. dies if the specified instant precedes the start of UTC or if the relevant segment hasn't been defined yet.

utc_segment_of_utc_day(DAY)

Returns the segment of the UTC description that pertains to the specified day number. dies if the specified day precedes the start of UTC or if the relevant segment hasn't been defined yet.

Shape of UTC

utc_day_leap_seconds(DAY)

Returns the number of extra UTC seconds inserted at the end of the day specified by number. The number is returned as a Math::BigRat and may be negative. dies if the specified day precedes the start of UTC or if UTC for the day has not yet been defined.

utc_day_seconds(DAY)

Returns the length, in UTC seconds, of the day specified by number. The number is returned as a Math::BigRat. dies if the specified day precedes the start of UTC or if UTC for the day has not yet been defined.

utc_check_instant(DAY, SECS)

Checks that a day/seconds combination is valid. dies if UTC is not defined for the specified day or if the number of seconds is out of range for that day.

Conversion between UTC and TAI

tai_to_utc(INSTANT)

Translates a TAI instant into UTC. The function returns a list of two values: the integral number of days since the TAI epoch and the number of UTC seconds within the day. dies if the specified instant precedes the start of UTC or if UTC is not yet defined for the instant.

utc_to_tai(DAY, SECS)

Translates a UTC instant into TAI. dies if the specified instant precedes the start of UTC or if UTC is not yet defined for the instant, or if the number of seconds is out of range for the day.

Display formatting

utc_secs_to_hms(SECS)

When a UTC day is longer than 86400 seconds, it is divided into hours and minutes in an idiosyncratic manner. Rather than times more than 86400 seconds after midnight being displayed as 24 hours and a fraction of a second, they are displayed as 23 hours, 59 minutes, and more than 60 seconds. This means that each UTC day contains the usual 1440 minutes; where leap seconds occur, the last minute of the day has a non-standard length. This arrangement is essential to make timezones work with UTC.

This function takes a number of seconds since midnight and returns a list of hours, minutes, and seconds values, in the UTC manner. It dies if given a negative number of seconds. It places no upper limit on the number of seconds, because the length of UTC days varies.

utc_hms_to_secs(HR, MI, SC)

This performs the reverse of the translation that utc_secs_to_hms does. It takes numbers of hours, minutes, and seconds, and returns the number of seconds since midnight. It dies if the numbers provided are invalid. It does not impose an upper limit on the time that may be specified, because the length of UTC days varies.

utc_day_to_ymd(DAY)

Although UTC is compatible with any means of labelling days, and the scalar day numbering used in this API can be readily converted into whatever form is required, it is conventional to label UTC days using the Gregorian calendar. Even when using some other calendar, the Gregorian calendar may be a convenient intermediate form, because of its prevalence.

This function takes a number of days since the TAI epoch and returns a list of a year, month, and day, in the Gregorian calendar. It places no bounds on the permissible day numbers; it is not limited to days for which UTC is defined. All year numbers generated are in the Common Era, and may be zero or negative if a sufficiently negative day number is supplied.

utc_ymd_to_day(YR, MO, DY)

This performs the reverse of the translation that utc_day_to_ymd does. It takes year, month, and day numbers, and returns the number of days since the TAI epoch. It dies if the numbers provided are invalid. It does not impose any limit on the range of years.

utc_instant_to_ymdhms(DAY, SECS)
utc_ymdhms_to_instant(YR, MO, DY, HR, MI, SC)

As a convenience, these two functions package together the corresponding pairs of display formatting functions described above. They do nothing extra that the underlying functions do not; they do not check that the instant specified is actually a valid UTC time.

SEE ALSO

DateTime, Time::UTC::Segment

AUTHOR

Andrew Main (Zefram) <zefram@fysh.org>

COPYRIGHT

Copyright (C) 2005 Andrew Main (Zefram) <zefram@fysh.org>

This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.