# [ntp:questions] Re: NTP, Unix and the 34-year itch (better read this)

Terje Mathisen terje.mathisen at hda.hydro.com
Fri Jan 23 08:53:13 UTC 2004

```Thomas A. Horsley wrote:

>>Almost all computers of today have some means, such as a time-of-year
>>(TOY) chip, to set the system clock at power up or reboot surely within
>>within 34 years, but some embedded systems do not.
>
>
> Speaking of 34 years, my little NTPTime client has the following
> magic number built into it:
>
> #define JAN_1_1900 2415021L
>
> Which is the julian day number of the base date for NTP timestamps.
>
> Obviously once we roll into a new 64 bit chunk of time, I'll need a
> new base date.
>
> Anyone know what the actual constant is for the next date coming up?

Easily calculated:

2^32 / 86400 = 49710
2^32 % 86400 = 23296

I.e. the second NTP epoch starts at julian day (241502+49710), at 06:28:16.

There are two easy ways to handle this conversion yourself:

a) Using 64-bit (or at least more than 32) math, define a window
starting about now, and check that a given NTP timestamp is not less
than this. If it is, add 2^32 seconds to the count until the time is
indeed at least in year 2004.

b) Split the ntp timestamp into two parts: julian day and seconds into
this day. This does not require any extended precision integer math.

Check that the resulting day number is in range, if not go into a loop
similar to (a), but this time add 49710 to the day number and 23296 to
the seconds count. Each time the seconds count is >= 86400, subtract
that and increment the day number.

However, the easiest method (by far!), and the one I have submitted as a
patch to ntp, is to simply say:

My OS has to support dates beyond the unix epoch end before it makes any
sense for me to do so, right?

In which case I can simply cast the ntp_seconds count to a unix time_t
value, and adjust for the base offset of (1970-1900).

The next step is to use the library calls (localtime/gmtime) to convert
this to printable format, and check that the year field is believable:

If time_t is 32-bit, and the OS supports epoch wraparound, then it must
employ windowing internally, and everything will 'simply work'.

If it does not, then the only alternative for a working OS is to use an
extended-precision time_t, which means that you can simply add 2^32
seconds to it and verify that you do get into range:

I.e. like this, (typed from memory):

time_t unix_seconds = (time_t) ntp_seconds - (
(mjd1970 - mjd1900) * 86400);

struct tm *mytm = gmtime(unix_seconds);

if (mytm->tm_year < 104) {  // 2004 - 1900 baseline
time_t temp = unix_seconds;
do {
temp += ((time_t) 65536) << 16;
if (temp == unix_second) return ERROR_TIME_T_IS_32_BIT;
mytm = gmtime(temp);
} while (mytm->tm_year < 104);
}

Terje

--
- <Terje.Mathisen at hda.hydro.com>
"almost all programming can be viewed as an exercise in caching"

```