[tz] What's "right"?

Guy Harris gharris at sonic.net
Fri Nov 13 22:51:08 UTC 2020


On Nov 13, 2020, at 5:17 AM, Michael H Deckers <michael.h.deckers at googlemail.com> wrote:

>    To explain my understanding of the "right" tzdb data, some context
>    is needed.
> 
>    The definition of UTC states that the offset UTC - TAI is a piecewise
>    constant function of TAI (for TAI >= 1972-01-01 + 10 s).

As I understand it, in that statement, neither TAI nor UTC are expressed as a count of seconds since some epoch, with the delta being between those two counts.  It means, for example, that:

	January 1, 1972, 00:00:00 UTC is January 1, 1972, 00:00:10 TAI;
	January 1, 1972, 00:00:01 UTC is January 1, 1972, 00:00:11 TAI;

		...

	June 30, 1972, 23:59:59 UTC is July 1, 1972, 00:00:09 TAI;
	June 30, 1972, 23:59:60 UTC is July 1, 1972, 00:00:10 TAI; (the June 30, 1972 leap second)
	July 1, 1972, 00:00:00 UTC is July 1, 1972, 00:00:11 TAI (following the June 30, 1972 leap second);
	July 1, 1972, 00:00:01 UTC is July 1, 1972, 00:00:11 TAI;

		...

	December 31, 1972, 23:59:59 UTC is January 1, 1973, 00:00:10 TAI;
	December 31, 1972, 23:59:60 UTC is January 1, 1973, 00:00:11 TAI;
	January 1, 1973, 00:00:00 UTC is January 1, 1973, 00:00:12 TAI (following the December 31, 1972 leap second);

and so on.

>    The computing interfaces for tzdb data typically allow for the
>    conversion between datetimes of UTC and datetimes of any tzdb Zone
>    time.

The computing interfaces, with the "posix" values, allow for the conversion of a value expressed as POSIX "seconds since the Epoch" - i.e., as a count of seconds, *excluding* leap seconds, that have elapsed since the Epoch - to a date and time, expressed as year/month/day/hour/minute/second, either as UTC (gmtime()) or as local time in any tzdb region (localtime()).

>    The converse conversion, from a datetime of a tzdb Zone time scale
>    to a corresponding datetime of UTC for the same instant,

Or, rather, the conversion of a date and time, expressed as year/month/day/hour/minute/second, as local time, to a value expressed as POSIX "seconds since the Epoch" (mktime()).

>    is not so
>    well defined since there may be no such corresponding datetime of
>    UTC, or there may be two such.

Yes, but that has to do with daylight saving time/summer time, *not* leap seconds.

>    As far as I understand the "right" tzdb data, they express
>    the offsets of tzdb Zone time scales as functions of TAI - 10 s
>    (not of UTC),

The tzdb data are used for converting between a time scale that uses integers (counts of seconds, whether they include or exclude leap seconds, since the Epoch) and a time scale that uses year/month/day/hour/minute/second, either as local time (localtime() to convert from the former to the latter; mktime() to convert from the latter to the former) or as UTC (gmtime() to convert from the former to the latter; the optional timegm() to convert from the latter to the former).

When the tzdb code uses the "posix" data, it converts between a time scale that represents instants of time as a count of seconds, *not* including leap seconds, since the Epoch, and time scales that represent instants of time as year/month/day/hour/minute/second, either UTC or local time.

When the tzdb code uses the "right" data, it converts between a time scale that represents instants of time as a count of seconds, *including* leap seconds, since the Epoch, and time scales that represent instants of time as year/month/day/hour/minute/second, either UTC or local time.

The Epoch is the same in both cases.

This conversion process requires knowledge of:

	the offset from UTC of local time for the time being converted, if the year/month/day/hour/minute/second value is in local time, but not if the year/month/day/hour/minute/second value is in UTC;

	the leap seconds inserted up to that time, if the count of seconds includes leap seconds, button if the count of seconds doesn't include leap seconds.

The "posix" tzdb data includes data to determine the former, but not data to determine the latter; the lack of the data to determine the latter, and the expression of transition times in the data to determine the former as counts of seconds *not* including leap seconds, causes the conversion to treat counts of seconds as not including leap seconds.

The "right" tzdb data includes data to determine the former, as well as data to determine the latter; the presence of the data to determine the latter, and the expression of transition times in the data to determine the former as counts of seconds *including* leap seconds, causes the conversion to treat counts of seconds as not including leap seconds.

Think in those terms, and it makes more sense.  Do not think of the input to gmtime() and localtime(), or the output of mktime(), as being "UTC" or as being "TAI - 10", think of it as being either "a count of seconds, other than leap seconds, since the Epoch" or "a count of seconds, including leap seconds, since the Epoch", the Epoch being the same in both cases.



More information about the tz mailing list