I've read a lot about UNIX Time lately, most of it incoherent, much of it contradictory. I am trying to reconcile conversions between UNIX Time (hereafter, for simplicity, UXT), TAI, and UTC, and to do this, I need to understand UXT properly. The trouble is, I can't seem to find anyone else who does.
The following represents my best-attempt explanation, reconstructed from innumerable sources by tedious research. It is also wrong somewhere. I am looking for a holistic analysis and point-by-point verification/refutation of the following. Essentially, fix the following so that it works.
TAI is a monotonically increasing time standard. It ticks SI seconds, and ignores DST and leap seconds.
UTC is the same as TAI, but corrected by an integer number of leap SI seconds (conversions to time strings reflect this as a 60th second) so as to be within 0.9 SI seconds of UT1, an astronomical time standard.
UXT is a count of UNIX seconds since 1970-01-01 00:00:00 UTC. There are always exactly 86400 seconds per day. Nevertheless, UXT is related to UTC.
How is this possible? Well, the UNIX second needs to be different from the SI second, and because leap seconds are not perfectly regular, UNIX seconds can't be a well-defined length of time.
The conversion from UTC to UXT in §4.15 of the UNIX spec aliases different UTC times to the same UXT timestamp, effectively making UNIX seconds the same as SI seconds (except for UNIX leap seconds, which are two SI seconds).
In practice, what actually happens varies. Most computers synchronize based on a remote server, and so they handle leap second updates implicitly during the synchronization.
All of this means that, while each individual UXT timestamp can be converted to/from UTC easily (use
gmtimeor §4.15, respectively), you can't really do arithmetic to find out anything using them. In particular,
difftimereturns UNIX seconds, and so you can't do anything with it, including adding it to a different timestamp, unless you know where all the relevant leap seconds are.
I think I understand so far.
- But now we look at actual code, which doesn't do any of this at all. I can understand people measuring durations using
difftimeand just sortof hoping that it's good enough (or not knowing there's a problem), but timekeeping libraries are wrong too.
As one example,
libtaiprovides a conversion (
tai_now.c:7) to TAI from UXT as:
TAI := 4,611,686,018,427,387,914 + UXT. Since TAI ticks SI seconds while UXT ticks UNIX seconds, you just can't do this. Yet, since
libtaiexplicitly handles leapseconds, it doesn't seem reasonable that this is a careless mistake.
It's not specific to
libtai. You see this sort of thing all over.
So: points 1-6 are in disagreement with point 7. That is, tons of existing code is in contradiction with the time standards it supposedly represents. What went wrong?