Annotation of embedaddon/ntp/libntp/caljulian.c, revision 1.1
1.1 ! misho 1: /*
! 2: * caljulian - determine the Julian date from an NTP time.
! 3: */
! 4: #include <sys/types.h>
! 5:
! 6: #include "ntp_types.h"
! 7: #include "ntp_calendar.h"
! 8: #include "ntp_stdlib.h"
! 9: #include "ntp_fp.h"
! 10: #include "ntp_unixtime.h"
! 11:
! 12: #if !(defined(ISC_CHECK_ALL) || defined(ISC_CHECK_NONE) || \
! 13: defined(ISC_CHECK_ENSURE) || defined(ISC_CHECK_INSIST) || \
! 14: defined(ISC_CHECK_INVARIANT))
! 15: # define ISC_CHECK_ALL
! 16: #endif
! 17:
! 18: #include "ntp_assert.h"
! 19:
! 20: #if 1
! 21:
! 22: /* Updated 2008-11-10 Juergen Perlinger <juergen.perlinger@t-online.de>
! 23: *
! 24: * Make the conversion 2038-proof with proper NTP epoch unfolding and extended
! 25: * precision calculations. Though we should really get a 'time_t' with more
! 26: * than 32 bits at least until 2037, because the unfolding cannot work after
! 27: * the wrap of the 32-bit 'time_t'.
! 28: */
! 29:
! 30: void
! 31: caljulian(
! 32: u_long ntptime,
! 33: register struct calendar *jt
! 34: )
! 35: {
! 36: u_long saved_time = ntptime;
! 37: u_long ntp_day; /* days (since christian era or in year) */
! 38: u_long n400; /* # of Gregorian cycles */
! 39: u_long n100; /* # of normal centuries */
! 40: u_long n4; /* # of 4-year cycles */
! 41: u_long n1; /* # of years into a leap year cycle */
! 42: u_long sclday; /* scaled days for month conversion */
! 43: int leaps; /* # of leaps days in year */
! 44: time_t now; /* current system time */
! 45: u_int32 tmplo; /* double precision tmp value / lo part */
! 46: int32 tmphi; /* double precision tmp value / hi part */
! 47:
! 48: NTP_INSIST(NULL != jt);
! 49:
! 50: /*
! 51: * First we have to unfold the ntp time stamp around the current time
! 52: * to make sure we are in the right epoch. Also we we do *NOT* fold
! 53: * before the begin of the first NTP epoch, so we WILL have a
! 54: * non-negative time stamp afterwards. Though at the time of this
! 55: * writing (2008 A.D.) it would be really strange to have systems
! 56: * running with clock set to he 1960's or before...
! 57: *
! 58: * But's important to use a 32 bit max signed value -- LONG_MAX is 64
! 59: * bit on a 64-bit system, and it will give wrong results.
! 60: */
! 61: now = time(NULL);
! 62: tmplo = (u_int32)now;
! 63: #if ( SIZEOF_TIME_T > 4 )
! 64: tmphi = (int32)(now >> 16 >> 16);
! 65: #else
! 66: /*
! 67: * Get the correct sign extension in the high part.
! 68: * (now >> 32) may not work correctly on every 32 bit
! 69: * system, e.g. it yields garbage under Win32/VC6.
! 70: */
! 71: tmphi = (int32)(now >> 31);
! 72: #endif
! 73:
! 74: M_ADD(tmphi, tmplo, 0, ((1UL << 31)-1)); /* 32-bit max signed */
! 75: M_ADD(tmphi, tmplo, 0, JAN_1970);
! 76: if ((ntptime > tmplo) && (tmphi > 0))
! 77: --tmphi;
! 78: tmplo = ntptime;
! 79:
! 80: /*
! 81: * Now split into days and seconds-of-day, using the fact that
! 82: * SECSPERDAY (86400) == 675 * 128; we can get roughly 17000 years of
! 83: * time scale, using only 32-bit calculations. Some magic numbers here,
! 84: * sorry for that. (This could be streamlined for 64 bit machines, but
! 85: * is worth the trouble?)
! 86: */
! 87: ntptime = tmplo & 127; /* save remainder bits */
! 88: tmplo = (tmplo >> 7) | (tmphi << 25);
! 89: ntp_day = (u_int32)tmplo / 675;
! 90: ntptime += ((u_int32)tmplo % 675) << 7;
! 91:
! 92: /* some checks for the algorithm
! 93: * There's some 64-bit trouble out there: the original NTP time stamp
! 94: * had only 32 bits, so our calculation invariant only holds in 32 bits!
! 95: */
! 96: NTP_ENSURE(ntptime < SECSPERDAY);
! 97: NTP_INVARIANT((u_int32)(ntptime + ntp_day * SECSPERDAY) == (u_int32)saved_time);
! 98:
! 99: /*
! 100: * Do the easy stuff first: take care of hh:mm:ss, ignoring leap
! 101: * seconds
! 102: */
! 103: jt->second = (u_char)(ntptime % SECSPERMIN);
! 104: ntptime /= SECSPERMIN;
! 105: jt->minute = (u_char)(ntptime % MINSPERHR);
! 106: ntptime /= MINSPERHR;
! 107: jt->hour = (u_char)(ntptime);
! 108:
! 109: /* check time invariants */
! 110: NTP_ENSURE(jt->second < SECSPERMIN);
! 111: NTP_ENSURE(jt->minute < MINSPERHR);
! 112: NTP_ENSURE(jt->hour < HRSPERDAY);
! 113:
! 114: /*
! 115: * Find the day past 1900/01/01 00:00 UTC
! 116: */
! 117: ntp_day += DAY_NTP_STARTS - 1; /* convert to days in CE */
! 118: n400 = ntp_day / GREGORIAN_CYCLE_DAYS; /* split off cycles */
! 119: ntp_day %= GREGORIAN_CYCLE_DAYS;
! 120: n100 = ntp_day / GREGORIAN_NORMAL_CENTURY_DAYS;
! 121: ntp_day %= GREGORIAN_NORMAL_CENTURY_DAYS;
! 122: n4 = ntp_day / GREGORIAN_NORMAL_LEAP_CYCLE_DAYS;
! 123: ntp_day %= GREGORIAN_NORMAL_LEAP_CYCLE_DAYS;
! 124: n1 = ntp_day / DAYSPERYEAR;
! 125: ntp_day %= DAYSPERYEAR; /* now zero-based day-of-year */
! 126:
! 127: NTP_ENSURE(ntp_day < 366);
! 128:
! 129: /*
! 130: * Calculate the year and day-of-year
! 131: */
! 132: jt->year = (u_short)(400*n400 + 100*n100 + 4*n4 + n1);
! 133:
! 134: if ((n100 | n1) > 3) {
! 135: /*
! 136: * If the cycle year ever comes out to 4, it must be December
! 137: * 31st of a leap year.
! 138: */
! 139: jt->month = 12;
! 140: jt->monthday = 31;
! 141: jt->yearday = 366;
! 142: } else {
! 143: /*
! 144: * The following code is according to the excellent book
! 145: * 'Calendrical Calculations' by Nachum Dershowitz and Edward
! 146: * Reingold. It converts the day-of-year into month and
! 147: * day-of-month, using a linear transformation with integer
! 148: * truncation. Magic numbers again, but they will not be used
! 149: * anywhere else.
! 150: */
! 151: sclday = ntp_day * 7 + 217;
! 152: leaps = ((n1 == 3) && ((n4 != 24) || (n100 == 3))) ? 1 : 0;
! 153: if (ntp_day >= (u_long)(JAN + FEB + leaps))
! 154: sclday += (2 - leaps) * 7;
! 155: ++jt->year;
! 156: jt->month = (u_char)(sclday / 214);
! 157: jt->monthday = (u_char)((sclday % 214) / 7 + 1);
! 158: jt->yearday = (u_short)(1 + ntp_day);
! 159: }
! 160:
! 161: /* check date invariants */
! 162: NTP_ENSURE(1 <= jt->month && jt->month <= 12);
! 163: NTP_ENSURE(1 <= jt->monthday && jt->monthday <= 31);
! 164: NTP_ENSURE(1 <= jt->yearday && jt->yearday <= 366);
! 165: }
! 166:
! 167: #else
! 168:
! 169: /* Updated 2003-12-30 TMa
! 170:
! 171: Uses common code with the *prettydate functions to convert an ntp
! 172: seconds count into a calendar date.
! 173: Will handle ntp epoch wraparound as long as the underlying os/library
! 174: does so for the unix epoch, i.e. works after 2038.
! 175: */
! 176:
! 177: void
! 178: caljulian(
! 179: u_long ntptime,
! 180: register struct calendar *jt
! 181: )
! 182: {
! 183: struct tm *tm;
! 184: NTP_REQUIRE(jt != NULL);
! 185:
! 186: tm = ntp2unix_tm(ntptime, 0);
! 187: NTP_INSIST(tm != NULL);
! 188:
! 189: jt->hour = (u_char) tm->tm_hour;
! 190: jt->minute = (u_char) tm->tm_min;
! 191: jt->month = (u_char) (tm->tm_mon + 1);
! 192: jt->monthday = (u_char) tm->tm_mday;
! 193: jt->second = (u_char) tm->tm_sec;
! 194: jt->year = (u_short) (tm->tm_year + 1900);
! 195: jt->yearday = (u_short) (tm->tm_yday + 1); /* Assumes tm_yday starts with day 0! */
! 196: }
! 197: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>