[tz] Leap seconds puzzle
john.haxby at oracle.com
Thu Apr 9 10:19:30 UTC 2015
On 08/04/15 20:46, Paul_Koning at dell.com wrote:
>> > On Apr 8, 2015, at 3:17 PM, Steve Allen <sla at ucolick.org> wrote:
>> > On Wed 2015-04-08T19:02:07 +0000, Paul_Koning at dell.com hath writ:
>>> >> So here is the puzzle. I would expect WWV, and www.time.gov, to
>>> >> reflect leap seconds. So why would they give me a time that matches,
>>> >> to the second, the POSIX time on my workstation? Does NTP send POSIX
>>> >> seconds since epoch rather than real ones?
>> > NTP effectively sends "mean solar seconds elapsed since epoch", which
>> > is another way of saying "elapsed seconds not counting leap seconds"
>> > as is demanded by POSIX.
> Thanks much! That sure is not clear from the RFC. So that explains things: it means that a POSIX system that is an NTP client will track UTC, leap seconds and all, except for a short while just after a leap second occurrence because at that point the NTP client machinery will be adjusting to the one second phase shift.
I looked into this in some depth for Linux because the ntpd -x flag
wasn't behaving as expected.
To get ntpd -x out of the way first: that stops ntpd from using the
kernel time discipline and it looks after time adjustments itself as
well as slewing any adjustment that would otherwise be a step. Once we
(at least two of us, independently) had fixed ntpd, leap seconds were
slewed as well. By slewing leapseconds you're trading accurate
timestamps for a monotonic clock -- the moral of which is don't use
gettimeofday() as an interval timer.
With that out of the way, it was interesting to see how time is handled
within the Linux kernel time discipline.
On the day of the leap second, ntpd sets a leap indicator to sat that
there will be a leap second inserted at midnight UTC (lunch time in New
Zealand, fortunately I'm in the UK). During this time, adjtimex(2)
return TIME_INS as its status.
At midnight, two things happen: the realtime clock steps from
1435708800 to 1435708799 and adjtimex() starts returning TIME_OOM as its
status. When time comes round to 1435708800 again, adjtimex() starts
returning TIME_OK as its status.
This is very useful because it means that at 1435708799.5 you can
unambiguously determine whether it's 23:59:59.5 or 23:59:60.5. Of
course, after the event a value in the interval [1435708799, 1435708800)
is ambiguous and Posix tacitly admits this. (What Posix actually says
is that the time in seconds returned by various system calls is
approximately the number of seconds since midnight at the beginning of 1970.
This is a problem.
The timestamp data type in a well-known RDBMS is a stored as a Posix
timestamp and a timezone indicator. The timezone indicator is useful
for expressing things like "same time tomorrow" but it doesn't help at
all with leap seconds. There is no way to express 23:39:60. (This is
one of the very few things I know about that database, in case you were
The problem is made more serious by the fact that 1435708799 occurs on
both Tuesday and Wednesday. If you want to store accurate timestamps,
you can't use the result of getttimeofday().
Dealing with whole hours is much simpler :)
More information about the tz