[LEAPSECS] [time-nuts] Leap Quirks
Magnus Danielson
magnus at rubidium.dyndns.org
Mon Jan 5 00:37:08 EST 2009
M. Warner Losh skrev:
> [[ continuation of a discussion from time-nuts ]]
>
> In message: <496157C4.2050300 at erols.com>
> Chuck Harris <cfharris at erols.com> writes:
> : Magnus Danielson wrote:
> : > Chuck Harris skrev:
> : >> One of us is confused about what time_t is... I think it is
> : >> you.
> : >
> : > I know of three different ways to interpret it. They fit different purposes.
> : >
> : >> time_t is a 32 bit (depreciated), or 64 bit integer that contains
> : >> the number of seconds since the epoch. It is not to be adjusted
> : >> for leap seconds according to POSIX, and unix convention.
> : >
> : > This is one, no two, of the interpretations I know of.
> :
> : Good!
> :
> : >> Everything to do with UTC and leap seconds is a library function
> : >> in most unixes that translates the leap second free time_t into
> : >> the leap second adjusted broken-down-time UTC.
> : >
> : > Exactly where? Do please tell me what the unified way of getting UTC
> : > time is. Oh, when there is a leap second it needs to give correct
> : > counting as well.
> :
> : If the unix supports leap second, which usually requires ntp, gmtime()
> : should report the UTC time correctly.
>
> POSIX doesn't support leap seconds. At all. They do not exist in
> POSIX's time_t.
I agree with this. Since time_t will have the leap second and second
prior to the leap second overlapped gmtime can not from time_t itself
provide a correct mapping out of time_t. An additional flag/field needs
to be used and when asking for current time an implementation could be
using some interface to the kernel to read for instance the ntp
interface flag, but doing that at any other point in time will not work
as the time_t given is not matching the time of flags in the kernel.
> : > Joe has in private conversations pointed out a POSIX interface which
> : > could be used.
> : >
> : >> Again, are you telling me that time_t is getting adjusted for leap
> : >> seconds? If so, when did this change?
> : >
> : > To the best of _my_ knowledge (which can be wrong) this is what is being
> : > done in practice, which is outside of the POSIX standard, but has the
> : > effect that 00:00:00 always midnight, which POSIX needs. This is a third
> : > interpretation...
> :
> : Yes, but this is not UTC midnight, but unix time or POSIX time midnight.
> : Unix time midnight, and POSIX time midnight drift from UTC midnight as the
> : leap seconds get added or removed.
>
> They are all the same thing. POSIX midnight, UTC midnight and Unix
> midnight all necessarily translate to the same value on a POSIXly
> correct system.
After reading up (thanks to Joe giving me the homework) I fully agree
with this. POSIX specify the mapping of UTC into time_t in an unambigous
fashion, but it does not specify the mapping of time_t into UTC in an
unambigous fashion.
I have identified 3 different interpretations of what time_t represents:
1) Number of SI seconds from 1970-01-01T00:00:00Z.
2) Number of UTC rubber seconds from 1970-01-01T00:00:00 to
1972-01-01T00:00:00Z (non-inclusive) and from there the number of SI
seconds, thus achieving an integer number of SI second difference
between POSIX time_t and TAI, namely 10.
3) UTC mapping into time_t in such a fashion that UTC midnight and POSIX
midnigth match.
POSIX.1-2008 actually defines the value of time_t as a strict mapping
from the UTC value (see Clause 4 General Concepts, Sub-Clause 4.15
Seconds Since the Epoch).
It goes on further if you go to the Clause A Rationale on sub-clause
A.4.15 Seconds Since the Epoch it details further and does explicitly
talk about how POSIX handles leap seconds or if you so whish, does not
handle leap seconds.
> : Some of the libc functions that convert time_t to broken down time convert
> : to UTC, and others convert to POSIX/Unix time... which is, I guess 24 seconds
> : fast?
>
> No. That's not POSIXly correct. There are some systems that
> implement this, but they aren't POSIX compliant.
The UTC => time_t mapping must be respected in the reverse mapping
time_t => UTC, which is what POSIX.1-2008 explicitly state.
> : Ntpd doesn't mess with time_t when it makes its leap second corrections,
> : but rather messes with tables and counters used by gmtime(), etal.. The
> : only time that ntpd messes with time_t is to slew it so that your system's
> : time_t is the same as everyone elses... (The number of si seconds since
> : the epoch without adjustments for leap seconds.)
>
> Actually, you are right. ntpd doesn't mess with it, but the kernel
> does. The kernel steps time backwards 1 second to accont for the leap
> second. It has to, since the leap second has no unique value in a
> time_t, in a POSIXly correct system. This is what is horribly broken
> about POSIX: leap second exist, but are explicitly ignored in POSIX.
Actually, to some degree you are both right and wrong. NTPD does fiddle
with it, using the interface into the kernel. NTPD sets the flags which
tells the kernel that there is an upcomming leap second and then the
kernel adjust the system clock. This is evident in NTP documentation on
leap-seconds, the interface specification for the kernel interface and
also when looking into the Linux kernel code. All this in order to be
POSIX compliant.
It is important to understand that the mapping between UTC and time_t is
lossy in the sense that when adding a leap second, that second is not
represented by a unique time_t value but it reuses a time_t value. All
other UTC times than the added leap seconds will be unambigously
represented in time_t for the time-span that time_t is defined.
If you need to represent UTC unambigously then a POSIX compliant time_t
will no make you happy.
If you would honour interpretation 1 or 2 of time_t instead and let
positive leap seconds remain encoded into time_t and use a leap-second
table, then UTC => time_t and time_t => UTC mappings could be made
totally unambigous. However, that would nto be POSIX.1-2008 compliant.
To also help understand the POSIX time_t, it does only say that it is
nominally the SI second, thus writing off the requirements for
non-steered systems.
> : > If somebody (say PHK) got out and slapped my face and say this is a
> : > total misunderstanding, this is pretty good after all. If this practice
> : > does exist, then we still have three interpretations and they are in
> : > conflict with each other even after giving up on introducing leap
> : > seconds. So we have two or three interpretation of the POSIX timescale,
> : > one with pure SI seconds, one with rubber seconds up till
> : > 1972-00-00T00:00:00Z and then SI seconds and a third which is like the
> : > second but re-aligned on each leap second event so that midnights match.
Reading up on the facts I realized that the third one was the one POSIX
used, not the first one as I earlier assumed. I thought I was going to
kill the third one but ended up confirming it as the standard.
Chuck is basing his resoning on interpretation 1 or possibly 2. So yes,
things DID change.
> : > This is only an issue if the POSIX scale is under external control.
> : >
> : > And yes, do tell me how I get UTC on all platforms.
> :
> : On all platforms? Even my VCR? That's a tall order. On unix
> : platforms, gmtime() will do the trick... assuming that leap seconds are
> : supported.
>
> Right. It can't do that in a POSIXly correct system, but system that
> doesn't completely comply with POSIX can choose to implement things
> this way.
I agree.
> The problem is that when a system is implemented this way, you
> suddenly have a number of programs that report time wrong by 24
> seconds because they make the POSIX assumption that time_t % 86400 is
> necessarily midnight (or some other assumption that is equivalent).
>
> There are many many programs that compute a time_t based on what I've
> called 'naive math' (since it is based on the naive assumption that
> leap seconds do not exist). It is not uncommon to see something akin
> to:
> // compute Dec 23, 1988 12:34:54
> time_t t = (18 * 365 + 5) * 86400 + 12 * 3600 + 34 * 60 + 54;
>
> (well, usually that's burried in the program's own implementation of
> gmtime, but you get the idea).
Actually it duplicates mktime(), but mktime() does the same thing
according to POSIX.1-2008.
> Also common is code that looks like:
>
> time_t wakeup;
>
> wakeup = time(NULL) + 86400; /* Same time tomorrow */
> while (1) {
> /* Do something */
> while (time(NULL) < wakeup)
> sleep (1);
> wakeup += 86400; /* Same time tomorrow */
> }
>
> or variations on this theme where they can assume a time of day
> computation and need no leap second tables. Such code is POSIXly
> correct, but breaks with the 'right' timezones from Olson.
>
> So time_t is effectively defined in POSIX to be:
>
> d * 86400 + min(tod(x), 86399)
>
> where d is the number of days since 01-01-1970, and tod is the second
> since midnight within the day.
I agree.
> : > Regardless, this just shows how complex the issue is. There seems that
> : > there is no "correct" interpretation that everyone can agree with as a
> : > basis. If there is I'll be much happier and go away a bit wiser.
> :
> : The only interpretation that would make me happy is one where UTC no longer
> : requires leap seconds... but that is a different subject.
>
> Yea, there's much opinion on the wisdom of that, or the lack of wisdom
> of that, to be had on this list...
It would not fully resolve the issue, but ease the problems, which is
not enterly the same thing.
Cheers,
Magnus
More information about the LEAPSECS
mailing list