Content deleted Content added
m Fix capitalisation using AWB |
much fuller information on the Mills (NTP) version |
||
Line 140:
Observe that when a positive leap second occurs (i.e., when a leap second is inserted) the Unix time numbers repeat themselves. The Unix time number 915 148 800.50 is ambiguous: it can refer either to the instant in the middle of the leap second, or to the instant one second later, half a second after midnight UTC. In the theoretical case when a negative leap second occurs (i.e., when a leap second is deleted) no ambiguity is caused, but instead there is a range of Unix time numbers that do not refer to any point in time at all.
When dealing with time periods that do not encompass a UTC leap second, the difference between two Unix time numbers is equal to the duration in seconds of the time period between the corresponding points in time. This is a common computational technique. However, where leap seconds occur, such calculations give the wrong answer. In applications where this level of accuracy is required, it is necessary to consult a table of leap seconds when dealing with Unix times, and it is often preferable to use a different time encoding that does not suffer this problem.
Line 148:
====NTP-based variant====
A popular model for managing a Unix clock is that given in ["A Kernel Model for Precision Timekeeping" ftp://ftp.udel.edu/pub/people/mills/memos/memo96b.ps] by [[David L. Mills]], the inventor of the [[Network Time Protocol]] (NTP). The objective of the model is to allow the Unix clock to be used as a component and an output of a synchronisation system such as NTP. Part of it specifies leap second behaviour.
In addition to the conventional Unix time number, this type of clock maintains a state variable that controls its leap second [[state machine]]. This variable can be retrieved along with the Unix time number using the '''ntp_gettime()''' function. The state variable normally has the value '''TIME_OK''' when no leap second is nearby. It can be used to disambiguate timestamps around a leap second.
This is what happens around a positive leap second:
{| border="1" cellspacing="0" cellpadding="2"
|+
|-
! align="left"|TAI
! align="left"|UTC
! align="
! align="right"|Unix clock
|-
| align="left"|1999-01-01T00:00:29.75
| align="left"|1998-12-31T23:59:58.75
| align="left"|TIME_INS
| align="right"|915 148 798.75
|-
| align="left"|1999-01-01T00:00:30.00
| align="left"|1998-12-31T23:59:59.00
| align="left"|TIME_INS
| align="right"|915 148 799.00
|-
| align="left"|1999-01-01T00:00:30.25
| align="left"|1998-12-31T23:59:59.25
| align="left"|TIME_INS
| align="right"|915 148 799.25
|-
| align="left"|1999-01-01T00:00:30.50
| align="left"|1998-12-31T23:59:59.50
| align="left"|TIME_INS
| align="right"|915 148 799.50
|-
| align="left"|1999-01-01T00:00:30.75
| align="left"|1998-12-31T23:59:59.75
| align="left"|TIME_INS
| align="right"|915 148 799.75
|-
| align="left"|1999-01-01T00:00:31.00
| align="left"|1998-12-31T23:59:60.00
| align="left"|TIME_OOP
| align="right"|915 148 799.00
|-
| align="left"|1999-01-01T00:00:31.25
| align="left"|1998-12-31T23:59:60.25
| align="left"|TIME_OOP
| align="right"|915 148 799.25
|-
| align="left"|1999-01-01T00:00:31.50
| align="left"|1998-12-31T23:59:60.50
| align="left"|TIME_OOP
| align="right"|915 148 799.50
|-
| align="left"|1999-01-01T00:00:31.75
| align="left"|1998-12-31T23:59:60.75
| align="left"|TIME_OOP
| align="right"|915 148 799.75
|-
| align="left"|1999-01-01T00:00:32.00
| align="left"|1999-01-01T00:00:00.00
| align="left"|TIME_WAIT
| align="right"|915 148 800.00
|-
| align="left"|1999-01-01T00:00:32.25
| align="left"|1999-01-01T00:00:00.25
| align="left"|TIME_WAIT
| align="right"|915 148 800.25
|-
| align="left"|1999-01-01T00:00:32.50
| align="left"|1999-01-01T00:00:00.50
| align="left"|TIME_WAIT
| align="right"|915 148 800.50
|-
| align="left"|1999-01-01T00:00:32.75
| align="left"|1999-01-01T00:00:00.75
| align="left"|TIME_WAIT
| align="right"|915 148 800.75
|-
| align="left"|1999-01-01T00:00:33.00
| align="left"|1999-01-01T00:00:01.00
| align="left"|TIME_WAIT
| align="right"|915 148 801.00
|-
| align="left"|1999-01-01T00:00:33.25
| align="left"|1999-01-01T00:00:01.25
| align="left"|TIME_WAIT
| align="right"|915 148 801.25
|}
The leap second state gets set to '''TIME_INS''' by the synchronisation system (e.g., NTP) some time in the hours before the leap, and afterwards it remains in the '''TIME_WAIT''' state until cleared by the synchronisation system. In the theoretical case of a negative leap the behaviour is similar: the state goes to '''TIME_DEL''' in advance, and then switches to '''TIME_WAIT''' as soon as the second has been skipped.
In a nominally-behaving Mills-style clock the only leap second state that needs to be distinguished in order to decode the time properly is '''TIME_OOP'''. '''TIME_INS''' and '''TIME_DEL''' theoretically act as advance warning of the leap, but with no guarantee of how far in advance the state changes this is of limited use. Applications requiring advance knowledge of leap seconds are better off using out-of-band mechanisms. However, the full set of states has another use. Commonly the leap second handling is not synchronous with the change of the Unix time number, so the behaviour is not quite as described here. This is discussed in the next subsection.
====Non-synchronous NTP-based variant====
Commonly a Mills-style Unix clock (as described in the preceding section) is implemented with leap second handling not synchronous with the change of the Unix time number. The time number initially increases normally where a leap should have occurred, and then it leaps a few milliseconds later. This is done in order to make implementation easier, and is suggested in passing by Mills's paper. This is what happens across a positive leap second:
{| border="1" cellspacing="0" cellpadding="2"
|+ non-synchronous Mills-style Unix clock across midnight when a UTC leap second is inserted
|-
! align="left"|TAI
! align="left"|UTC
! align="left"|state
! align="right"|Unix clock
|-
| align="left"|1999-01-01T00:00:29.75
| align="left"|1998-12-31T23:59:58.75
| align="left"|TIME_INS
| align="right"|915 148 798.75
|-
| align="left"|1999-01-01T00:00:30.00
| align="left"|1998-12-31T23:59:59.00
| align="left"|TIME_INS
| align="right"|915 148 799.00
|-
| align="left"|1999-01-01T00:00:30.25
| align="left"|1998-12-31T23:59:59.25
| align="left"|TIME_INS
| align="right"|915 148 799.25
|-
| align="left"|1999-01-01T00:00:30.50
| align="left"|1998-12-31T23:59:59.50
| align="left"|TIME_INS
| align="right"|915 148 799.50
|-
| align="left"|1999-01-01T00:00:30.75
| align="left"|1998-12-31T23:59:59.75
| align="left"|TIME_INS
| align="right"|915 148 799.75
|-
| align="left"|1999-01-01T00:00:31.00
| align="left"|1998-12-31T23:59:60.00
| align="left"|TIME_INS
| align="right"|915 148 800.00
|-
| align="left"|1999-01-01T00:00:31.25
| align="left"|1998-12-31T23:59:60.25
| align="left"|TIME_OOP
| align="right"|915 148 799.25
|-
| align="left"|1999-01-01T00:00:31.50
| align="left"|1998-12-31T23:59:60.50
| align="left"|TIME_OOP
| align="right"|915 148 799.50
|-
| align="left"|1999-01-01T00:00:31.75
| align="left"|1998-12-31T23:59:60.75
| align="left"|TIME_OOP
| align="right"|915 148 799.75
|-
| align="left"|1999-01-01T00:00:32.00
| align="left"|1999-01-01T00:00:00.00
| align="left"|TIME_OOP
| align="right"|915 148 800.00
|-
| align="left"|1999-01-01T00:00:32.25
| align="left"|1999-01-01T00:00:00.25
| align="left"|TIME_WAIT
| align="right"|915 148 800.25
|-
| align="left"|1999-01-01T00:00:32.50
| align="left"|1999-01-01T00:00:00.50
| align="left"|TIME_WAIT
| align="right"|915 148 800.50
|-
| align="left"|1999-01-01T00:00:32.75
| align="left"|1999-01-01T00:00:00.75
| align="left"|TIME_WAIT
| align="right"|915 148 800.75
|-
| align="left"|1999-01-01T00:00:33.00
| align="left"|1999-01-01T00:00:01.00
| align="left"|TIME_WAIT
| align="right"|915 148 801.00
|-
| align="left"|1999-01-01T00:00:33.25
| align="left"|1999-01-01T00:00:01.25
| align="left"|TIME_WAIT
| align="right"|915 148 801.25
|}
This can be decoded properly by paying attention to the leap second state variable, which unambiguously indicates whether the leap has been performed yet. The state variable change is synchronous with the leap.
A similar situation arises with a negative leap second, where the second that is skipped is slightly too late. Very briefly the system shows a nominally impossible time number, but this can be detected by the '''TIME_DEL''' state and corrected.
In this type of system the Unix time number violates POSIX around both types of leap second. Collecting the leap second state variable along with the time number allows for unambiguous decoding, so the correct POSIX time number can be generated if desired, or the full UTC time can be stored in a more suitable format.
====TAI-based variant====
|