diff options
Diffstat (limited to 'libntp/caljulian.c')
-rw-r--r-- | libntp/caljulian.c | 186 |
1 files changed, 15 insertions, 171 deletions
diff --git a/libntp/caljulian.c b/libntp/caljulian.c index 7673061b57ce..6463699b152a 100644 --- a/libntp/caljulian.c +++ b/libntp/caljulian.c @@ -1,13 +1,14 @@ /* * caljulian - determine the Julian date from an NTP time. + * + * (Note: since we use the GREGORIAN calendar, this should be renamed to + * 'calgregorian' eventually...) */ +#include <config.h> #include <sys/types.h> #include "ntp_types.h" #include "ntp_calendar.h" -#include "ntp_stdlib.h" -#include "ntp_fp.h" -#include "ntp_unixtime.h" #if !(defined(ISC_CHECK_ALL) || defined(ISC_CHECK_NONE) || \ defined(ISC_CHECK_ENSURE) || defined(ISC_CHECK_INSIST) || \ @@ -17,181 +18,24 @@ #include "ntp_assert.h" -#if 1 - -/* Updated 2008-11-10 Juergen Perlinger <juergen.perlinger@t-online.de> - * - * Make the conversion 2038-proof with proper NTP epoch unfolding and extended - * precision calculations. Though we should really get a 'time_t' with more - * than 32 bits at least until 2037, because the unfolding cannot work after - * the wrap of the 32-bit 'time_t'. - */ - void caljulian( - u_long ntptime, - register struct calendar *jt + uint32_t ntp, + struct calendar * jt ) { - u_long saved_time = ntptime; - u_long ntp_day; /* days (since christian era or in year) */ - u_long n400; /* # of Gregorian cycles */ - u_long n100; /* # of normal centuries */ - u_long n4; /* # of 4-year cycles */ - u_long n1; /* # of years into a leap year cycle */ - u_long sclday; /* scaled days for month conversion */ - int leaps; /* # of leaps days in year */ - time_t now; /* current system time */ - u_int32 tmplo; /* double precision tmp value / lo part */ - int32 tmphi; /* double precision tmp value / hi part */ - - NTP_INSIST(NULL != jt); - - /* - * First we have to unfold the ntp time stamp around the current time - * to make sure we are in the right epoch. Also we we do *NOT* fold - * before the begin of the first NTP epoch, so we WILL have a - * non-negative time stamp afterwards. Though at the time of this - * writing (2008 A.D.) it would be really strange to have systems - * running with clock set to he 1960's or before... - * - * But's important to use a 32 bit max signed value -- LONG_MAX is 64 - * bit on a 64-bit system, and it will give wrong results. - */ - now = time(NULL); - tmplo = (u_int32)now; -#if ( SIZEOF_TIME_T > 4 ) - tmphi = (int32)(now >> 16 >> 16); -#else - /* - * Get the correct sign extension in the high part. - * (now >> 32) may not work correctly on every 32 bit - * system, e.g. it yields garbage under Win32/VC6. - */ - tmphi = (int32)(now >> 31); -#endif + vint64 vlong; + ntpcal_split split; - M_ADD(tmphi, tmplo, 0, ((1UL << 31)-1)); /* 32-bit max signed */ - M_ADD(tmphi, tmplo, 0, JAN_1970); - if ((ntptime > tmplo) && (tmphi > 0)) - --tmphi; - tmplo = ntptime; - /* - * Now split into days and seconds-of-day, using the fact that - * SECSPERDAY (86400) == 675 * 128; we can get roughly 17000 years of - * time scale, using only 32-bit calculations. Some magic numbers here, - * sorry for that. (This could be streamlined for 64 bit machines, but - * is worth the trouble?) - */ - ntptime = tmplo & 127; /* save remainder bits */ - tmplo = (tmplo >> 7) | (tmphi << 25); - ntp_day = (u_int32)tmplo / 675; - ntptime += ((u_int32)tmplo % 675) << 7; - - /* some checks for the algorithm - * There's some 64-bit trouble out there: the original NTP time stamp - * had only 32 bits, so our calculation invariant only holds in 32 bits! - */ - NTP_ENSURE(ntptime < SECSPERDAY); - NTP_INVARIANT((u_int32)(ntptime + ntp_day * SECSPERDAY) == (u_int32)saved_time); - - /* - * Do the easy stuff first: take care of hh:mm:ss, ignoring leap - * seconds - */ - jt->second = (u_char)(ntptime % SECSPERMIN); - ntptime /= SECSPERMIN; - jt->minute = (u_char)(ntptime % MINSPERHR); - ntptime /= MINSPERHR; - jt->hour = (u_char)(ntptime); - - /* check time invariants */ - NTP_ENSURE(jt->second < SECSPERMIN); - NTP_ENSURE(jt->minute < MINSPERHR); - NTP_ENSURE(jt->hour < HRSPERDAY); - - /* - * Find the day past 1900/01/01 00:00 UTC - */ - ntp_day += DAY_NTP_STARTS - 1; /* convert to days in CE */ - n400 = ntp_day / GREGORIAN_CYCLE_DAYS; /* split off cycles */ - ntp_day %= GREGORIAN_CYCLE_DAYS; - n100 = ntp_day / GREGORIAN_NORMAL_CENTURY_DAYS; - ntp_day %= GREGORIAN_NORMAL_CENTURY_DAYS; - n4 = ntp_day / GREGORIAN_NORMAL_LEAP_CYCLE_DAYS; - ntp_day %= GREGORIAN_NORMAL_LEAP_CYCLE_DAYS; - n1 = ntp_day / DAYSPERYEAR; - ntp_day %= DAYSPERYEAR; /* now zero-based day-of-year */ - - NTP_ENSURE(ntp_day < 366); + NTP_INSIST(NULL != jt); /* - * Calculate the year and day-of-year + * Unfold ntp time around current time into NTP domain. Split + * into days and seconds, shift days into CE domain and + * process the parts. */ - jt->year = (u_short)(400*n400 + 100*n100 + 4*n4 + n1); - - if ((n100 | n1) > 3) { - /* - * If the cycle year ever comes out to 4, it must be December - * 31st of a leap year. - */ - jt->month = 12; - jt->monthday = 31; - jt->yearday = 366; - } else { - /* - * The following code is according to the excellent book - * 'Calendrical Calculations' by Nachum Dershowitz and Edward - * Reingold. It converts the day-of-year into month and - * day-of-month, using a linear transformation with integer - * truncation. Magic numbers again, but they will not be used - * anywhere else. - */ - sclday = ntp_day * 7 + 217; - leaps = ((n1 == 3) && ((n4 != 24) || (n100 == 3))) ? 1 : 0; - if (ntp_day >= (u_long)(JAN + FEB + leaps)) - sclday += (2 - leaps) * 7; - ++jt->year; - jt->month = (u_char)(sclday / 214); - jt->monthday = (u_char)((sclday % 214) / 7 + 1); - jt->yearday = (u_short)(1 + ntp_day); - } - - /* check date invariants */ - NTP_ENSURE(1 <= jt->month && jt->month <= 12); - NTP_ENSURE(1 <= jt->monthday && jt->monthday <= 31); - NTP_ENSURE(1 <= jt->yearday && jt->yearday <= 366); -} - -#else - -/* Updated 2003-12-30 TMa - - Uses common code with the *prettydate functions to convert an ntp - seconds count into a calendar date. - Will handle ntp epoch wraparound as long as the underlying os/library - does so for the unix epoch, i.e. works after 2038. -*/ - -void -caljulian( - u_long ntptime, - register struct calendar *jt - ) -{ - struct tm *tm; - NTP_REQUIRE(jt != NULL); - - tm = ntp2unix_tm(ntptime, 0); - NTP_INSIST(tm != NULL); - - jt->hour = (u_char) tm->tm_hour; - jt->minute = (u_char) tm->tm_min; - jt->month = (u_char) (tm->tm_mon + 1); - jt->monthday = (u_char) tm->tm_mday; - jt->second = (u_char) tm->tm_sec; - jt->year = (u_short) (tm->tm_year + 1900); - jt->yearday = (u_short) (tm->tm_yday + 1); /* Assumes tm_yday starts with day 0! */ + vlong = ntpcal_ntp_to_ntp(ntp, NULL); + split = ntpcal_daysplit(&vlong); + ntpcal_daysplit_to_date(jt, &split, DAY_NTP_STARTS); } -#endif |