aboutsummaryrefslogtreecommitdiff
path: root/libntp/caljulian.c
diff options
context:
space:
mode:
Diffstat (limited to 'libntp/caljulian.c')
-rw-r--r--libntp/caljulian.c186
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