UTC, TAI, and UNIX time

What is TAI?

TAI times are identified by year, month, day, hour, minute, and second. There are exactly 86400 TAI seconds in every TAI day. TAI days are labelled by the Gregorian calendar.

What is UTC?

UTC, Coordinated Universal Time, is based on TAI, and very similar to it, except that UTC has leap seconds every year or two. For example, here's how UTC and TAI handled the end of June 1997:

1997-06-30 23:59:59 UTC = 1997-07-01 00:00:29 TAI

1997-06-30 23:59:60 UTC = 1997-07-01 00:00:30 TAI

1997-07-01 00:00:00 UTC = 1997-07-01 00:00:31 TAI



Notice the 23:59:60 in UTC. That's a leap second. It extended 1997-06-30 UTC to 86401 seconds. Before the leap second, the TAI-UTC difference was 30 seconds; after the leap second, the TAI-UTC difference was 31 seconds.

By inserting occasional leap seconds into UTC, astronomers slow down UTC's progression to match Earth's rotation. That way the Sun will always be overhead at 12:00:00 UTC in England. (It's conceivable, but unlikely, that someday Earth's rotation will speed up past 1/86400 Hz. In that case astronomers will create negative leap seconds: UTC will skip from 23:59:58 to 00:00:00.)

Other time zones are based on UTC---e.g., UTC minus 5 hours---so noon has a predictable relationship to the Sun in every time zone.

The leap-second system was introduced at the beginning of 1972. At that point UTC was TAI minus 10 seconds.

What is UNIX time?

What is the epoch? Originally it was defined as the beginning of 1970 GMT. GMT, Greenwich Mean Time, is a traditional term for the time zone in England. Unfortunately, it is ambiguous; it can refer to a variety of astronomical time scales.

Arthur David Olson's popular time library uses an epoch of 1970-01-01 00:00:10 TAI.

What's the problem?

Unfortunately, xntpd, a program that synchronizes clocks using the Network Time Protocol, pandered to those broken localtime() libraries, at the expense of reliability. Watch how the xntpd time scale increases as a leap second occurs:

1997-06-30 23:59:59.7 UTC -> 867715199.7 xntpd

1997-06-30 23:59:59.8 UTC -> 867715199.8 xntpd

1997-06-30 23:59:59.9 UTC -> 867715199.9 xntpd

1997-06-30 23:59:60.0 UTC -> 867715200.0 xntpd

1997-06-30 23:59:60.1 UTC -> 867715200.1 xntpd

1997-06-30 23:59:60.2 UTC -> 867715200.2 xntpd

1997-06-30 23:59:60.3 UTC -> 867715200.3 xntpd

1997-06-30 23:59:60.4 UTC -> 867715200.4 xntpd

1997-06-30 23:59:60.5 UTC -> 867715200.5 xntpd

1997-06-30 23:59:60.6 UTC -> 867715200.6 xntpd

1997-06-30 23:59:60.7 UTC -> 867715200.7 xntpd

1997-06-30 23:59:60.8 UTC -> 867715200.8 xntpd

1997-06-30 23:59:60.9 UTC -> 867715200.9 xntpd

1997-07-01 00:00:00.0 UTC -> 867715200.0 xntpd

1997-07-01 00:00:00.1 UTC -> 867715200.1 xntpd

1997-07-01 00:00:00.2 UTC -> 867715200.2 xntpd



The xntpd time scale repeats itself! It cannot be reliably converted to UTC.

By resetting the clock at each leap second, xntpd extracts a correct UTC display (except, of course, during leap seconds) from the broken localtime() libraries. Meanwhile, it produces incorrect results for applications that add and subtract real times.

Why not fix it?

The main obstacle is POSIX. POSIX is a ``standard'' designed by a vendor consortium several years ago to eliminate progress and protect the installed base. The behavior of the broken localtime() libraries was documented and turned into a POSIX requirement.

Fortunately, the POSIX rules are so outrageously dumb---for example, they require that 2100 be a leap year, contradicting the Gregorian calendar---that no self-respecting engineer would obey them.

References

The Olson library is available from ftp://elsie.nci.nih.gov/pub/. The above argument against the xntpd time scale is shamelessly stolen from one of Olson's manual pages.

In preparation for the Y2036 and Y2038 disasters, I've put together some 64-bit time manipulation code, including very fast UTC-to-TAI conversion. My library supports the same TAI epoch as the Olson library.

I've also put together a very simple clock-synchronization package, including a Network Time Protocol client that handles leap seconds correctly.