Unix time: Difference between revisions

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.
 
ItA Unix clock is often implemented with a commondifferent mistaketype toof implementpositive aleap Unixsecond clockhandling associated with the [[Network Time Protocol]]'s differing handling of positive leap seconds. This yields a system that does not conform to the POSIX standard. See the section below concerning NTP for details.
 
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.
To complicate things, the [[Network Time Protocol]] handles positive leap seconds differently. It has its own numeric time representation, very similar to Unix time but with a different [[epoch (reference date)|epoch date]] and different leap second behaviour. NTP time repeats the second preceding the leap second, rather than the second following the leap second. Unix clocks controlled by NTP are usually implemented by just adding a constant offset to the NTP time, and therefore usually behave like this:
 
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"
|+ NTPMills-basedstyle Unix clock across midnight when a UTC leap second is inserted
|-
! align="left"|TAI
! align="left"|UTC
! align="rightleft"|NTP-based Unix clockstate
! 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
|}
 
SuchThis behaviour of the Unix time number does not conform to POSIX.1, but is very common. As a result, Unix times such as 915 148 799.50, apparently in the second preceding a leap second, are [[de facto]] ambiguous, as are (both [[de facto]] and [[de jure]]) times such as 915 148 800.50. For programs that need to handle the leap second properly, the '''TIME_OOP''' state makes it clear which is the leap second.
 
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====