File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / libntp / caltontp.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, 5 months ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    1: /*
    2:  * caltontp - convert a date to 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_assert.h"
   10: 
   11: /*
   12:  * Juergen Perlinger, 2008-11-12
   13:  * Add support for full calendar calculatios. If the day-of-year is provided
   14:  * (that is, not zero) it will be used instead of month and day-of-month;
   15:  * otherwise a full turn through the calendar calculations will be taken.
   16:  *
   17:  * I know that Harlan Stenn likes to see assertions in production code, and I
   18:  * agree there, but it would be a tricky thing here. The algorithm is quite
   19:  * capable of producing sensible answers even to seemingly weird inputs: the
   20:  * date <any year here>-03-00, the 0.th March of the year, will be automtically
   21:  * treated as the last day of February, no matter whether the year is a leap
   22:  * year or not. So adding constraints is merely for the benefit of the callers,
   23:  * because the only thing we can check for consistency is our input, produced
   24:  * by somebody else.
   25:  *
   26:  * BTW: A total roundtrip using 'caljulian' would be a quite shaky thing:
   27:  * Because of the truncation of the NTP time stamp to 32 bits and the epoch
   28:  * unfolding around the current time done by 'caljulian' the roundtrip does
   29:  * *not* necessarily reproduce the input, especially if the time spec is more
   30:  * than 68 years off from the current time...
   31:  */
   32: u_long
   33: caltontp(
   34: 	const struct calendar *jt
   35: 	)
   36: {
   37: 	ntp_u_int32_t days;	/* full days in NTP epoch */
   38: 	ntp_u_int32_t years;	/* complete ACE years before date */
   39: 	ntp_u_int32_t month;	/* adjusted month for calendar */
   40: 	
   41: 	NTP_INSIST(jt != NULL);
   42: 
   43: 	NTP_REQUIRE(jt->month <= 13);	/* permit month 0..13! */
   44: 	NTP_REQUIRE(jt->monthday <= 32);
   45: 	NTP_REQUIRE(jt->yearday <= 366);
   46: 	NTP_REQUIRE(jt->hour <= 24);
   47: 	NTP_REQUIRE(jt->minute <= MINSPERHR);
   48: 	NTP_REQUIRE(jt->second <= SECSPERMIN);
   49: 
   50: 	/*
   51: 	 * First convert the date to fully elapsed days since NTP epoch. The
   52: 	 * expressions used here give us initially days since 0001-01-01, the
   53: 	 * beginning of the christian era in the proleptic gregorian calendar;
   54: 	 * they are rebased on-the-fly into days since beginning of the NTP
   55: 	 * epoch, 1900-01-01.
   56: 	 */
   57: 	if (jt->yearday) {
   58: 		/*
   59: 		 * Assume that the day-of-year contains a useable value and
   60: 		 * avoid all calculations involving month and day-of-month.
   61: 		 */
   62: 		years = jt->year - 1;
   63: 		days  = years * DAYSPERYEAR	/* days in previous years */
   64: 		      + years / 4		/* plus prior years's leap days */
   65: 		      - years / 100		/* minus leapless century years */
   66: 		      + years / 400		/* plus leapful Gregorian yrs */
   67: 		      + jt->yearday		/* days this year */
   68: 		      - DAY_NTP_STARTS;		/* rebase to NTP epoch */
   69: 	} else {
   70: 		/*
   71: 		 * The following code is according to the excellent book
   72: 		 * 'Calendrical Calculations' by Nachum Dershowitz and Edward
   73: 		 * Reingold. It does a full calendar evaluation, using one of
   74: 		 * the alternate algorithms: Shift to a hypothetical year
   75: 		 * starting on the previous march,1st; merge years, month and
   76: 		 * days; undo the the 9 month shift (which is 306 days). The
   77: 		 * advantage is that we do NOT need to now whether a year is a
   78: 		 * leap year or not, because the leap day is the LAST day of
   79: 		 * the year.
   80: 		 */
   81: 		month  = (ntp_u_int32_t)jt->month + 9;
   82: 		years  = jt->year - 1 + month / 12;
   83: 		month %= 12;
   84: 		days   = years * DAYSPERYEAR	/* days in previous years */
   85: 		       + years / 4		/* plus prior years's leap days */
   86: 		       - years / 100		/* minus leapless century years */
   87: 		       + years / 400		/* plus leapful Gregorian yrs */
   88: 		       + (month * 153 + 2) / 5	/* plus days before month */
   89: 		       + jt->monthday		/* plus day-of-month */
   90: 		       - 306			/* minus 9 months */
   91: 		       - DAY_NTP_STARTS;	/* rebase to NTP epoch */
   92: 	}
   93: 
   94: 	/*
   95: 	 * Do the obvious: Merge everything together, making sure integer
   96: 	 * promotion doesn't play dirty tricks on us; there is probably some
   97: 	 * redundancy in the casts, but this drives it home with force. All
   98: 	 * arithmetic is done modulo 2**32, because the result is truncated
   99: 	 * anyway.
  100: 	 */
  101: 	return               days       * SECSPERDAY
  102: 	    + (ntp_u_int32_t)jt->hour   * MINSPERHR*SECSPERMIN
  103: 	    + (ntp_u_int32_t)jt->minute * SECSPERMIN
  104: 	    + (ntp_u_int32_t)jt->second;
  105: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>