TAI zone?

Guy Harris guy at alum.mit.edu
Fri Jul 1 16:43:49 UTC 2011

On Jul 1, 2011, at 4:59 AM, Clive D.W. Feather wrote:

> The SI second is defined in terms of vibrations of the caesium atom. Let's
> imagine a counter that ticks exactly once every SI second. This counter was
> started at the beginning of 1958 and has ticked steadily ever since.
> Now let's feed this counter through the normal date-time decoding process:
>    seconds = N % 60
>    minutes = (N / 60) % 60
>    hours = (N / 3600) % 24
>    daynumber = N / 86400
>    { year, month, day } = Gregorian_decode (daynumber)
> This is the TAI clock. It ticks steadily and regularly, always with 60
> seconds to the minute, 60 minutes to the hour, 24 hours to the day,
> 28/29/30/31 days to the month, 12 months to the year. Right now it's saying
> 2011-07-01 11:28:45. Note that TAI is a clock, not a count of seconds.

(...if "clock" includes not only HH:MM:SS but also a date.)

> Now imagine a second clock. This also ticks once per second. Right now it's
> 34 seconds behind the TAI clock, so it is saying 2011-07-01 11:28:11.
> This clock has 60 minutes to the hour, 24 hours to the day, 28/29/30/31 days
> to the month, and 12 months to the year, but while it usually has 60
> seconds to the minute, it sometimes has 59 or 61 - these minutes are always
> the last minute of a month. So at the end of this year it could tick any of:
>    2011-12-31 23:59:56    2011-12-31 23:59:56    2011-12-31 23:59:56
>    2011-12-31 23:59:57    2011-12-31 23:59:57    2011-12-31 23:59:57
>    2011-12-31 23:59:58    2011-12-31 23:59:58    2011-12-31 23:59:58
>    2012-01-01 00:00:00    2011-12-31 23:59:59    2011-12-31 23:59:59
>    2012-01-01 00:00:01    2012-01-01 00:00:00    2011-12-31 23:59:60
>    2012-01-01 00:00:02    2012-01-01 00:00:01    2012-01-01 00:00:00
>    2012-01-01 00:00:03    2012-01-01 00:00:02    2012-01-01 00:00:01
>    2012-01-01 00:00:04    2012-01-01 00:00:03    2012-01-01 00:00:02
> (and we don't yet know which of them it will be). This is the UTC clock.
> Note that TAI-UTC is always an integer number of seconds.

(And one could make a UTC clock out of the SI-second counter with the Olson code and an Olson database built with the leap seconds database, as long as you keep the copy of the Olson database up-to-date with leap-second updates.)

So "34 seconds behind the TAI clock" says nothing about any counters of SI seconds; it says something about what the TAI and UTC clocks display.

> Now POSIX. The value of time_t is defined as ticking once per (SI) second,
> keeping in sync with UTC, but ignoring leap seconds. This definitions is a
> (slight) lie.

What "4.15 Seconds Since the Epoch" says is:

	A value that approximates the number of seconds that have elapsed since the Epoch. A Coordinated Universal Time name (specified in terms of seconds (tm_sec), minutes (tm_min), hours (tm_hour), days since January 1 of the year (tm_yday), and calendar year minus 1900 (tm_year)) is related to a time represented as seconds since the Epoch, according to the expression below.

	If the year is <1970 or the value is negative, the relationship is undefined. If the year is >=1970 and the value is non-negative, the value is related to a Coordinated Universal Time name according to the C-language expression, where tm_sec, tm_min, tm_hour,tm_yday, and tm_year are all integer types:

	tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 + (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 - ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400

which means that 2008-12-31 23:59:60 and 2009-01-01 00:00:00 would map to the same time_t value.

The rationale for that second explicitly says that:

	A.4.15 Seconds Since the Epoch

	Coordinated Universal Time (UTC) includes leap seconds. However, in POSIX time (seconds since the Epoch), leap seconds are ignored (not applied) to provide an easy and compatible method of computing time differences. Broken-down POSIX time is therefore not necessarily UTC, despite its appearance.

> What actually happens is that the counter increases once per
> second most of the time, but at the end of a month:
> - if the last minute has 60 seconds, it increases by 1 from 23:59:59 to
>  00:00:00;
> - if the last minute has 59 seconds, it increases by 2 from 23:59:58 to
>  00:00:00 (a period of 1 second);
> - if the last minute has 61 seconds, it increases by 1 from 23:59:59 to
>  23:59:60, then does not change from 23:59:60 to 00:00:00 (so increasing
>  by only 1 in 2 seconds).

...which matches "4.15 Seconds Since the Epoch".

> Actual computer systems may follow this. Or they may alter the speed of
> their internal clock to slew them back into sync with the value of time_t,
> just as they do when they discover an error in their internal clock.

...or they may fail to do either, and thus, in practice, violate POSIX.  I suspect that, these days, NTP is used enough that they do arrange that time_t not tick exactly once per SI second (yeah, one could view that as "NTP is not only used to *correct* clock drift, it's also used to *cause* clock drift as required by POSIX").

And, yes, that means that POSIX requires that if your OS's implementation of time() ends up driven by an atomic clock, it would either have to read a leap-second database to know when to do something other than increment the time_t counter when the atomic clock says "ping", or would have to have the atomic-clock-driven counter not be returned by time() but be adjusted with a leap-second database before being returned by time(), or would have to otherwise take leap second information into account.

It also means that if your really want to know how many seconds elapse between two events, don't use POSIX time_t.

More information about the tz mailing list