https://cr.yp.to/proto/utctai.html
D. J. Bernstein
Time
UTC, TAI, and UNIX time
What is TAI?
TAI, Temps Atomique International (French for International Atomic
Time), measures real time. One second of TAI time is a constant
duration defined by cesium radiation. TAI has been measured
continuously since 1955 and is the foundation of all civil time
standards.
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?
One day of Earth's rotation isn't exactly 86400 seconds. It's closer
to 86400.002 seconds, wobbling slightly from day to day.
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?
UNIX time counts the number of seconds since an ``epoch.'' This is
very convenient for programs that work with time intervals: the
difference between two UNIX time values is a real-time difference
measured in seconds, within the accuracy of the local clock.
Thousands of programmers rely on this fact.
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?
For many years, the UNIX localtime() time-display routine didn't
support leap seconds. In effect it treated TAI as UTC. Its displays
slipped 1 second away from the correct local time as each leap second
passed. Nobody cared; clocks weren't set that accurately anyway.
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?
It's easy enough to fix xntpd. It's also easy to fix localtime() to
handle leap seconds. In fact, some vendors have already adopted
Olson's time library.
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 NIST Time and Frequency Division Home Page is a good starting
point for programmers who want to learn about time measurement.
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.