2008-12-05

POSIX time_t is not UTC

For years, I've been pretending that time_t is a better representation of time than any combination of year, month, day, etc. That's because it's a linear representation of time that can be subjected to arithmetic. In particular, it's monotonically increasing.

Well, that's not true on POSIX systems. On POSIX, time_t is said to be based on UTC, but it ignores leap seconds! Considering that UTC is defined as TAI minus accumulated leap seconds, that's one giant opt-out.

The official line (from SuS v3) on leap seconds is "applications which do care about leap seconds can determine how to handle them in whatever way those applications feel is best". OK, quick question: your application, which cares about leap seconds, calls time() and gets 915148800; what time is it? If you need to know, you're out of luck; compliant POSIX systems stepped their clocks back a second during the leap second. If you have a drug-delivery system that's based on POSIX, don't use it if a second's too much drug will harm the patient.

In fact, POSIX time_t is an encoding of a Gregorian calendar time (year, month, day, hour, minute, second). The POSIX committee considers it more important that time_t is consistent between machines, than that it should be correct. Consequently, the description in the man pages and standards of time_t as "seconds since the Epoch" is a lie.

It violates POSIX to set your system clock to return the actual number of seconds since 1970-01-01T00:00:00Z! Right now (2008-12-05) it should be the number of seconds since 1970-01-01T00:00:23Z; from the start of 2009 it should be the number of seconds since 1970-01-01T00:00:24Z. If you try to use difftime to compare a time from 2008 with a time from 2009, you'll get the right answer minus one.

This is clearly crazy. If you want to ignore leap-seconds, use TAI and accept the drift. If you want to ignore leap-seconds but stay close to UTC, stick to year/month/day/hour/minute/second (i.e. struct tm). If you want accurate intervals and not necessarily accurate calendar times, use a monotonically-increasing count of seconds since some definite time in the past. Unix made its choice clearly and precisely; POSIX is wrong to change it, and STUPID BAD WRONG to change it while pretending it's the same.

[Edited: I had the wrong offsets in the fifth paragraph.]

[Update: Someone pointed me at an old message titled History of IEEE P1003.1 POSIX time which explains a lot.