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

David L. Mills mills at udel.edu
Fri Jan 23 20:32:45 UTC 2004


Curious. NTP internally has no dependence on Julian day numbers at all.
I'm sure you have seen the page I've been yakking about
www.eecis.udel.edu/~mills/y2k.html. It suggests a method similar to the
last one you mention.

There's a bit of overlooked principle here, one motivated by the need
perceived in the theory community, to make strong correctness assertions
about the time. According to these principles NTP never sets the time,
only adds or subtracts values from the current time. This was done for,
among other reasons, that rollovers become transparent and you don't
have to worry about them as long as the four most recent timestamps are
struck in the same era.

Boiled down to essentials, the assertions worked out several years ago
in a meeting in beautiful southern Germany, NTP never knows the time,
just an amount less than 68 years to add or subtract from the apparent
current time. However, there has to be a way to set the real current
time within an interval assumed correct, in this case less than 34 years
from UTC to avoid overflow. Once this is done NTP can maintain the time
without ambiguity unless it is banned on an island and put to sleep for
34 years.

You've got me thinking again about the roll issues. We should be able to
compute from the origin of the Julian ers, 1.5 January 4713 to the death
of the universe using only the additive group modulo 68 years and
survive rollover while needing nothing except a reliable timestamp
within 68 years of the current time.


Terje Mathisen wrote:
> 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"

More information about the questions mailing list