File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / libntp / caljulian.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 1 month ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    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>