skip to content

What does NTP's 64-bit timestamp hold, and what does its seconds field wrapping in February 2036 actually break?

level: seniorimportance: should knowfreq 14%

answer

  1. seconds and a binary fraction
  2. counted from 1900
  3. 2^32 seconds is about 136 years
  4. no era on the wire
  5. differences survive, dates do not

basics

~20 s

It holds 32 bits of seconds since 0h 1 January 1900 UTC and a 32-bit binary fraction. The 2036 wrap leaves offset and delay differences intact but makes a raw timestamp ambiguous as a date, because NTPv4 sends no era number.

solid answer

~40 s

RFC 5905's timestamp is 32 unsigned bits of seconds since the prime epoch, 0h 1 January 1900 UTC, plus a 32-bit fraction resolving about 232 picoseconds. 2^32 seconds is about 136 years, so era 0 ends early in February 2036, and RFC 5905's table lists 8 February 2036 as the first day of era 1. The offset and delay are computed from twos-complement differences, which stay correct across adjacent eras as long as the client starts within the RFC's window of the server's time. What breaks is turning a raw value into a date: the header carries no era, so a host that has no date of its own cannot tell 2036 from 1900. RFC 5905 says eras must come from external means, such as the filesystem or dedicated hardware.

code

pseudocode · 12 lines
pseudocode
// expand a 32-bit NTP seconds value to full seconds since 1900
// local_s: this host's own estimate, wide integer, trusted within 2^31 s
function expand(ntp_seconds, ntp_fraction, local_s):
    if ntp_seconds == 0 and ntp_fraction == 0:
        return UNKNOWN                      // zero means unsynchronized
    era = floor(local_s / 2^32)
    s = era * 2^32 + ntp_seconds
    if s - local_s > 2^31:
        s = s - 2^32                        // value is from the previous era
    else if local_s - s > 2^31:
        s = s + 2^32                        // value is from the next era
    return s

go deeper

for a junior

Recall the layout: 32 bits of seconds since 1900 and 32 bits of binary fraction, with zero meaning unknown.

for a middle

Explain why 2^32 seconds ends era 0 in February 2036, and convert between the 1900 and 1970 epochs.

for a senior

Separate what survives the wrap, the subtraction-based exchange, from what breaks, date conversion without an era, and name the devices at risk.

for a principal

Plan for 2036 as a fleet question: which devices cannot know the year on boot, and which external date source each one will trust.

## What the 64-bit timestamp holds RFC 5905, the NTPv4 specification, defines three time formats. The one in every packet header is the **64-bit timestamp format**: | Format | Size | Seconds | Fraction | Used for | |---|---|---|---|---| | Timestamp | 64 bits | 32 unsigned bits | 32 bits, about 232 ps | Reference, Origin, Receive and Transmit timestamps | | Short | 32 bits | 16 unsigned bits | 16 bits | Root Delay and Root Dispersion | | Date | 128 bits | 64 signed bits, split into Era Number and Era Offset | 64 bits | internal use where storage allows | - The seconds count from the **prime epoch**, 0h 1 January 1900 UTC. - The fraction is **binary**: each unit is 2^-32 of a second, so half a second is `0x80000000` and one millisecond is about 4,294,967 units. It is not a count of milliseconds or microseconds. - A value of **zero** means unknown or unsynchronized time. - A system clock that counts seconds from 1 January 1970 must add **2,208,988,800**, the timestamp RFC 5905 lists for that date. ## When era 0 ends 32 bits of seconds wrap after 2^32 = 4,294,967,296 seconds, about 136 years. RFC 5905 calls each such span an **era**: era 0 runs from 1900 to some time in 2036, when the field wraps and era 1 begins. Its table of historic dates lists **8 February 2036** as the first day of era 1, at an era offset of 63,104 seconds. Working back 63,104 seconds puts the wrap itself at 06:28:16 UTC on 7 February 2036. ## What keeps working: the exchange arithmetic RFC 5905 says the only arithmetic permitted on timestamps is **twos-complement subtraction**, and that operations on them produce results in the same or adjacent eras. The offset and delay are built from differences such as `T2 - T1` and `T4 - T1`, so a request sent a second before the wrap and answered a second after still yields a correct small difference. 1. A first-order difference of two timestamps is a signed value with 63 significant bits, good for about 68 years either way. 2. RFC 5905 section 8 notes that if the second-order sums in the offset and delay formulas are also done in 64-bit fixed point, the unambiguous range shrinks to **34 years**. 3. Converting the differences to floating double before those sums restores **68 years**, which matches section 6's statement that correct values are obtained across adjacent eras when the client is set within 68 years of the server. The practical rule: the exchange works across the wrap provided the client's clock already starts reasonably close to the server's. ## What breaks: turning a timestamp into a date The 32-bit seconds field repeats every era, and the NTPv4 header carries no era number. RFC 5905 says plainly that eras cannot be produced by NTP; when needed, they come from **external means**, such as the filesystem or dedicated hardware. That leaves real failure modes for an operator to plan for: - A device that boots with no idea of the date, for example a clock reset to its zero point, may be further from the server than the window allows, so the computed offset is wrong. - Code that converts a raw NTP timestamp to a calendar date by assuming era 0 will place a timestamp from after the 2036 wrap back in 1900. - Code that treats the seconds field as signed, or that stores it in a narrower type, breaks earlier than the era boundary. - Logs, databases or file formats that store raw 32-bit NTP seconds inherit the same ambiguity; they need a wider field or an era kept alongside. A host that keeps a wide internal count and a rough idea of the date, and expands each 32-bit value into the era that puts it nearest that date, handles the wrap without trouble. The rough idea is the hard part on small devices: a battery-backed clock, a stored last-known time or a build date are the usual external means, and a device with none of them needs one before 2036, not after. ## What changes in NTPv5 The NTPv5 Internet-Draft, draft-ietf-ntp-ntpv5-09, puts an 8-bit **era number** in its header, which it says extends the unambiguous interval from 136 years to about 35,000 years. It is a draft, not a published RFC, so NTPv4 deployments still rely on each host knowing roughly what year it is.

  • Do NTP's offset and delay formulas break at the 2036 wrap?
    No, if they use twos-complement subtraction, the only arithmetic RFC 5905 permits on timestamps. Differences across adjacent eras come out right while the client starts within the window: 68 years per section 6, or 34 years if section 8's second-order sums stay in 64-bit fixed point instead of floating double.
  • What does an NTP timestamp of zero mean?
    RFC 5905 reserves zero in both the date and timestamp formats for unknown or unsynchronized time. A client seeing zero in a field should treat that value as absent, not as the first instant of 1900.
  • How does the NTPv5 draft address the era problem?
    draft-ietf-ntp-ntpv5-09 carries an 8-bit era number in its header, which it says extends the unambiguous interval from 136 years to about 35,000 years. It is still an Internet-Draft, so NTPv4 hosts must supply the era themselves.

saying these in an interview costs you the question

  • The 2036 wrap breaks NTP's offset and delay arithmetic for every host.
  • The NTP timestamp counts seconds since 1 January 1970.
  • The fraction field holds a count of milliseconds.
  • The NTPv4 header carries an era number that resolves the wrap.
  • Root delay and root dispersion use the full 64-bit timestamp format.