Home | History | Annotate | Line # | Download | only in include
      1 /*	$NetBSD: ntp_calendar.h,v 1.8 2020/05/25 20:47:19 christos Exp $	*/
      2 
      3 /*
      4  * ntp_calendar.h - definitions for the calendar time-of-day routine
      5  */
      6 #ifndef NTP_CALENDAR_H
      7 #define NTP_CALENDAR_H
      8 
      9 #include <time.h>
     10 
     11 #include "ntp_types.h"
     12 
     13 /* gregorian calendar date */
     14 struct calendar {
     15 	uint16_t year;		/* year (A.D.) */
     16 	uint16_t yearday;	/* day of year, 1 = January 1 */
     17 	uint8_t  month;		/* month, 1 = January */
     18 	uint8_t  monthday;	/* day of month */
     19 	uint8_t  hour;		/* hour of day, midnight = 0 */
     20 	uint8_t  minute;	/* minute of hour */
     21 	uint8_t  second;	/* second of minute */
     22 	uint8_t  weekday;	/* 0..7, 0=Sunday */
     23 };
     24 typedef struct calendar TCivilDate;
     25 typedef struct calendar const TcCivilDate;
     26 
     27 /* ISO week calendar date */
     28 struct isodate {
     29 	uint16_t year;		/* year (A.D.) */
     30 	uint8_t	 week;		/* 1..53, week in year */
     31 	uint8_t	 weekday;	/* 1..7, 1=Monday */
     32 	uint8_t	 hour;		/* hour of day, midnight = 0 */
     33 	uint8_t	 minute;	/* minute of hour */
     34 	uint8_t	 second;	/* second of minute */
     35 };
     36 typedef struct isodate TIsoDate;
     37 typedef struct isodate const TcIsoDate;
     38 
     39 /* general split representation */
     40 typedef struct {
     41 	int32_t hi;
     42 	int32_t lo;
     43 } ntpcal_split;
     44 
     45 typedef time_t (*systime_func_ptr)(time_t *);
     46 
     47 /*
     48  * set the function for getting the system time. This is mostly used for
     49  * unit testing to provide a fixed / shifted time stamp. Setting the
     50  * value to NULL restores the original function, that is, 'time()',
     51  * which is also the automatic default.
     52  */
     53 extern systime_func_ptr ntpcal_set_timefunc(systime_func_ptr);
     54 
     55 /*
     56  * days-of-week
     57  */
     58 #define CAL_SUNDAY	0
     59 #define CAL_MONDAY	1
     60 #define CAL_TUESDAY	2
     61 #define CAL_WEDNESDAY	3
     62 #define CAL_THURSDAY	4
     63 #define CAL_FRIDAY	5
     64 #define CAL_SATURDAY	6
     65 #define CAL_SUNDAY7	7	/* also sunday */
     66 
     67 /*
     68  * Days in each month.	30 days hath September...
     69  */
     70 #define	JAN	31
     71 #define	FEB	28
     72 #define	FEBLEAP	29
     73 #define	MAR	31
     74 #define	APR	30
     75 #define	MAY	31
     76 #define	JUN	30
     77 #define	JUL	31
     78 #define	AUG	31
     79 #define	SEP	30
     80 #define	OCT	31
     81 #define	NOV	30
     82 #define	DEC	31
     83 
     84 /*
     85  * We deal in a 4 year cycle starting at March 1, 1900.	 We assume
     86  * we will only want to deal with dates since then, and not to exceed
     87  * the rollover day in 2036.
     88  */
     89 #define	SECSPERMIN	(60)			/* seconds per minute */
     90 #define	MINSPERHR	(60)			/* minutes per hour */
     91 #define	HRSPERDAY	(24)			/* hours per day */
     92 #define	DAYSPERWEEK	(7)			/* days per week */
     93 #define	DAYSPERYEAR	(365)			/* days per year */
     94 
     95 #define	SECSPERHR	(SECSPERMIN * MINSPERHR)
     96 #define	SECSPERDAY	(SECSPERHR * HRSPERDAY)
     97 #define	SECSPERWEEK	(DAYSPERWEEK * SECSPERDAY)
     98 #define	SECSPERYEAR	(365 * SECSPERDAY)	/* regular year */
     99 #define	SECSPERLEAPYEAR	(366 * SECSPERDAY)	/* leap year */
    100 #define	SECSPERAVGYEAR	31556952		/* mean year length over 400yrs */
    101 
    102 #define GPSWEEKS	1024			/* GPS week cycle */
    103 /*
    104  * Gross hacks.	 I have illicit knowlege that there won't be overflows
    105  * here, the compiler often can't tell this.
    106  */
    107 #define	TIMES60(val)	((((val)<<4) - (val))<<2)	/* *(16 - 1) * 4 */
    108 #define	TIMES24(val)	(((val)<<4) + ((val)<<3))	/* *16 + *8 */
    109 #define	TIMES7(val)	(((val)<<3) - (val))		/* *8  - *1 */
    110 #define	TIMESDPERC(val)	(((val)<<10) + ((val)<<8) \
    111 			+ ((val)<<7) + ((val)<<5) \
    112 			+ ((val)<<4) + ((val)<<2) + (val))	/* *big* hack */
    113 
    114 
    115 extern	const char * const months[12];
    116 extern	const char * const daynames[7];
    117 
    118 extern	char *	 ntpcal_iso8601std(char*, size_t, struct calendar const*);
    119 extern	void	 caljulian	(uint32_t, struct calendar *);
    120 extern	uint32_t caltontp	(const struct calendar *);
    121 
    122 /*
    123  * Convert between 'time_t' and 'vint64'
    124  */
    125 extern vint64 time_to_vint64(const time_t *);
    126 extern time_t vint64_to_time(const vint64 *);
    127 
    128 /*
    129  * Get the build date & time. ATTENTION: The time zone is not specified!
    130  * This depends entirely on the C compilers' capabilities to properly
    131  * expand the '__TIME__' and '__DATE__' macros, as required by the C
    132  * standard.
    133  */
    134 extern int
    135 ntpcal_get_build_date(struct calendar * /* jd */);
    136 
    137 /*
    138  * Convert a timestamp in NTP scale to a time_t value in the UN*X
    139  * scale with proper epoch unfolding around a given pivot or the
    140  * current system time.
    141  */
    142 extern vint64
    143 ntpcal_ntp_to_time(uint32_t /* ntp */, const time_t * /* pivot */);
    144 
    145 /*
    146  * Convert a timestamp in NTP scale to a 64bit seconds value in the NTP
    147  * scale with proper epoch unfolding around a given pivot or the current
    148  * system time.
    149  * Note: The pivot must be given in UN*X time scale!
    150  */
    151 extern vint64
    152 ntpcal_ntp_to_ntp(uint32_t /* ntp */, const time_t * /* pivot */);
    153 
    154 /*
    155  * Split a time stamp in seconds into elapsed days and elapsed seconds
    156  * since midnight.
    157  */
    158 extern ntpcal_split
    159 ntpcal_daysplit(const vint64 *);
    160 
    161 /*
    162  * Split a time stamp in seconds into elapsed weeks and elapsed seconds
    163  * since start of week.
    164  */
    165 extern ntpcal_split
    166 ntpcal_weeksplit(const vint64 *);
    167 
    168 /*
    169  * Merge a number of days and a number of seconds into seconds,
    170  * expressed in 64 bits to avoid overflow.
    171  */
    172 extern vint64
    173 ntpcal_dayjoin(int32_t /* days */, int32_t /* seconds */);
    174 
    175 /*
    176  * Merge a number of weeks and a number of seconds into seconds,
    177  * expressed in 64 bits to avoid overflow.
    178  */
    179 extern vint64
    180 ntpcal_weekjoin(int32_t /* weeks */, int32_t /* seconds */);
    181 
    182 /* Get the number of leap years since epoch for the number of elapsed
    183  * full years
    184  */
    185 extern int32_t
    186 ntpcal_leapyears_in_years(int32_t /* years */);
    187 
    188 /*
    189  * Convert elapsed years in Era into elapsed days in Era.
    190  */
    191 extern int32_t
    192 ntpcal_days_in_years(int32_t /* years */);
    193 
    194 /*
    195  * Convert a number of elapsed month in a year into elapsed days
    196  * in year.
    197  *
    198  * The month will be normalized, and 'res.hi' will contain the
    199  * excessive years that must be considered when converting the years,
    200  * while 'res.lo' will contain the days since start of the
    201  * year. (Expect the resulting days to be negative, with a positive
    202  * excess! But then, we need no leap year flag, either...)
    203  */
    204 extern ntpcal_split
    205 ntpcal_days_in_months(int32_t /* months */);
    206 
    207 /*
    208  * Convert ELAPSED years/months/days of gregorian calendar to elapsed
    209  * days in Gregorian epoch. No range checks done here!
    210  */
    211 extern int32_t
    212 ntpcal_edate_to_eradays(int32_t /* years */, int32_t /* months */, int32_t /* mdays */);
    213 
    214 /*
    215  * Convert a time spec to seconds. No range checks done here!
    216  */
    217 extern int32_t
    218 ntpcal_etime_to_seconds(int32_t /* hours */, int32_t /* minutes */, int32_t /* seconds */);
    219 
    220 /*
    221  * Convert ELAPSED years/months/days of gregorian calendar to elapsed
    222  * days in year.
    223  *
    224  * Note: This will give the true difference to the start of the given year,
    225  * even if months & days are off-scale.
    226  */
    227 extern int32_t
    228 ntpcal_edate_to_yeardays(int32_t /* years */, int32_t /* months */, int32_t /* mdays */);
    229 
    230 /*
    231  * Convert the date part of a 'struct tm' (that is, year, month,
    232  * day-of-month) into the RataDie of that day.
    233  */
    234 extern int32_t
    235 ntpcal_tm_to_rd(const struct tm * /* utm */);
    236 
    237 /*
    238  * Convert the date part of a 'struct calendar' (that is, year, month,
    239  * day-of-month) into the RataDie of that day.
    240  */
    241 extern int32_t
    242 ntpcal_date_to_rd(const struct calendar * /* jt */);
    243 
    244 /*
    245  * Given the number of elapsed days in the calendar era, split this
    246  * number into the number of elapsed years in 'res.quot' and the
    247  * number of elapsed days of that year in 'res.rem'.
    248  *
    249  * if 'isleapyear' is not NULL, it will receive an integer that is 0
    250  * for regular years and a non-zero value for leap years.
    251  *
    252  * The input is limited to [-2^30, 2^30-1]. If the days exceed this
    253  * range, errno is set to EDOM and the result is saturated.
    254  */
    255 extern ntpcal_split
    256 ntpcal_split_eradays(int32_t /* days */, int/*BOOL*/ * /* isleapyear */);
    257 
    258 /*
    259  * Given a number of elapsed days in a year and a leap year indicator,
    260  * split the number of elapsed days into the number of elapsed months
    261  * in 'res.quot' and the number of elapsed days of that month in
    262  * 'res.rem'.
    263  */
    264 extern ntpcal_split
    265 ntpcal_split_yeardays(int32_t /* eyd */, int/*BOOL*/ /* isleapyear */);
    266 
    267 /*
    268  * Convert a RataDie number into the date part of a 'struct
    269  * calendar'. Return 0 if the year is regular year, !0 if the year is
    270  * a leap year.
    271  */
    272 extern int/*BOOL*/
    273 ntpcal_rd_to_date(struct calendar * /* jt */, int32_t /* rd */);
    274 
    275 /*
    276  * Convert a RataDie number into the date part of a 'struct
    277  * tm'. Return 0 if the year is regular year, !0 if the year is a leap
    278  * year.
    279  */
    280 extern int/*BOOL*/
    281 ntpcal_rd_to_tm(struct tm * /* utm */, int32_t /* rd */);
    282 
    283 /*
    284  * Take a value of seconds since midnight and split it into hhmmss in
    285  * a 'struct calendar'. Return excessive days.
    286  */
    287 extern int32_t
    288 ntpcal_daysec_to_date(struct calendar * /* jt */, int32_t /* secs */);
    289 
    290 /*
    291  * Take the time part of a 'struct calendar' and return the seconds
    292  * since midnight.
    293  */
    294 extern int32_t
    295 ntpcal_date_to_daysec(const struct calendar *);
    296 
    297 /*
    298  * Take a value of seconds since midnight and split it into hhmmss in
    299  * a 'struct tm'. Return excessive days.
    300  */
    301 extern int32_t
    302 ntpcal_daysec_to_tm(struct tm * /* utm */, int32_t /* secs */);
    303 
    304 extern int32_t
    305 ntpcal_tm_to_daysec(const struct tm * /* utm */);
    306 
    307 /*
    308  * convert a year number to rata die of year start
    309  */
    310 extern int32_t
    311 ntpcal_year_to_ystart(int32_t /* year */);
    312 
    313 /*
    314  * For a given RataDie, get the RataDie of the associated year start,
    315  * that is, the RataDie of the last January,1st on or before that day.
    316  */
    317 extern int32_t
    318 ntpcal_rd_to_ystart(int32_t /* rd */);
    319 
    320 /*
    321  * convert a RataDie to the RataDie of start of the calendar month.
    322  */
    323 extern int32_t
    324 ntpcal_rd_to_mstart(int32_t /* year */);
    325 
    326 
    327 extern int
    328 ntpcal_daysplit_to_date(struct calendar * /* jt */,
    329 			const ntpcal_split * /* ds */, int32_t /* dof */);
    330 
    331 extern int
    332 ntpcal_daysplit_to_tm(struct tm * /* utm */, const ntpcal_split * /* ds */,
    333 		      int32_t /* dof */);
    334 
    335 extern int
    336 ntpcal_time_to_date(struct calendar * /* jd */, const vint64 * /* ts */);
    337 
    338 extern int32_t
    339 ntpcal_periodic_extend(int32_t /* pivot */, int32_t /* value */,
    340 		       int32_t /* cycle */);
    341 
    342 extern int
    343 ntpcal_ntp64_to_date(struct calendar * /* jd */, const vint64 * /* ntp */);
    344 
    345 extern int
    346 ntpcal_ntp_to_date(struct calendar * /* jd */,	uint32_t /* ntp */,
    347 		   const time_t * /* pivot */);
    348 
    349 extern vint64
    350 ntpcal_date_to_ntp64(const struct calendar * /* jd */);
    351 
    352 extern uint32_t
    353 ntpcal_date_to_ntp(const struct calendar * /* jd */);
    354 
    355 extern time_t
    356 ntpcal_date_to_time(const struct calendar * /* jd */);
    357 
    358 /*
    359  * ISO week-calendar conversions
    360  */
    361 extern int32_t
    362 isocal_weeks_in_years(int32_t  /* years */);
    363 
    364 /*
    365  * The input is limited to [-2^30, 2^30-1]. If the weeks exceed this
    366  * range, errno is set to EDOM and the result is saturated.
    367  */
    368 extern ntpcal_split
    369 isocal_split_eraweeks(int32_t /* weeks */);
    370 
    371 extern int
    372 isocal_ntp64_to_date(struct isodate * /* id */, const vint64 * /* ntp */);
    373 
    374 extern int
    375 isocal_ntp_to_date(struct isodate * /* id */, uint32_t /* ntp */,
    376 		   const time_t * /* pivot */);
    377 
    378 extern vint64
    379 isocal_date_to_ntp64(const struct isodate * /* id */);
    380 
    381 extern uint32_t
    382 isocal_date_to_ntp(const struct isodate * /* id */);
    383 
    384 
    385 /*
    386  * day-of-week calculations
    387  *
    388  * Given a RataDie and a day-of-week, calculate a RDN that is reater-than,
    389  * greater-or equal, closest, less-or-equal or less-than the given RDN
    390  * and denotes the given day-of-week
    391  */
    392 extern int32_t
    393 ntpcal_weekday_gt(int32_t  /* rdn */, int32_t /* dow */);
    394 
    395 extern int32_t
    396 ntpcal_weekday_ge(int32_t /* rdn */, int32_t /* dow */);
    397 
    398 extern int32_t
    399 ntpcal_weekday_close(int32_t /* rdn */, int32_t  /* dow */);
    400 
    401 extern int32_t
    402 ntpcal_weekday_le(int32_t /* rdn */, int32_t /* dow */);
    403 
    404 extern int32_t
    405 ntpcal_weekday_lt(int32_t /* rdn */, int32_t /* dow */);
    406 
    407 
    408 /*
    409  * handling of base date spec
    410  */
    411 extern int32_t
    412 basedate_eval_buildstamp(void);
    413 
    414 extern int32_t
    415 basedate_eval_string(const char *str);
    416 
    417 extern int32_t
    418 basedate_set_day(int32_t dayno);
    419 
    420 extern uint32_t
    421 basedate_get_day(void);
    422 
    423 extern time_t
    424 basedate_get_eracenter(void);
    425 
    426 extern time_t
    427 basedate_get_erabase(void);
    428 
    429 extern uint32_t
    430 basedate_get_gpsweek(void);
    431 
    432 extern uint32_t
    433 basedate_expand_gpsweek(unsigned short weekno);
    434 
    435 /*
    436  * Additional support stuff for Ed Rheingold's calendrical calculations
    437  */
    438 
    439 /*
    440  * Start day of NTP time as days past 0000-12-31 in the proleptic
    441  * Gregorian calendar. (So 0001-01-01 is day number 1; this is the Rata
    442  * Die counting scheme used by Ed Rheingold in his book "Calendrical
    443  * Calculations".)
    444  */
    445 #define	DAY_NTP_STARTS 693596
    446 
    447 /*
    448  * Start day of the UNIX epoch. This is the Rata Die of 1970-01-01.
    449  */
    450 #define DAY_UNIX_STARTS 719163
    451 
    452 /*
    453  * Start day of the GPS epoch. This is the Rata Die of 1980-01-06
    454  */
    455 #define DAY_GPS_STARTS 722820
    456 
    457 /*
    458  * Difference between UN*X and NTP epoch (25567).
    459  */
    460 #define NTP_TO_UNIX_DAYS (DAY_UNIX_STARTS - DAY_NTP_STARTS)
    461 
    462 /*
    463  * Difference between GPS and NTP epoch (29224)
    464  */
    465 #define NTP_TO_GPS_DAYS (DAY_GPS_STARTS - DAY_NTP_STARTS)
    466 
    467 /*
    468  * Days in a normal 4 year leap year calendar cycle (1461).
    469  */
    470 #define	GREGORIAN_NORMAL_LEAP_CYCLE_DAYS	(4 * 365 + 1)
    471 
    472 /*
    473  * Days in a normal 100 year leap year calendar (36524).  We lose a
    474  * leap day in years evenly divisible by 100 but not by 400.
    475  */
    476 #define	GREGORIAN_NORMAL_CENTURY_DAYS	\
    477 			(25 * GREGORIAN_NORMAL_LEAP_CYCLE_DAYS - 1)
    478 
    479 /*
    480  * The Gregorian calendar is based on a 400 year cycle. This is the
    481  * number of days in each cycle (146097).  We gain a leap day in years
    482  * divisible by 400 relative to the "normal" century.
    483  */
    484 #define	GREGORIAN_CYCLE_DAYS (4 * GREGORIAN_NORMAL_CENTURY_DAYS + 1)
    485 
    486 /*
    487  * Number of weeks in 400 years (20871).
    488  */
    489 #define	GREGORIAN_CYCLE_WEEKS (GREGORIAN_CYCLE_DAYS / 7)
    490 
    491 /*
    492  * Is a Greogorian calendar year a leap year? The obvious solution is to
    493  * test the expression
    494  *
    495  * (y % 4 == 0) && ((y % 100 != 0) || (y % 400 == 0))
    496  *
    497  * This needs (in theory) 2 true divisions -- most compilers check the
    498  * (mod 4) condition by doing a bit test. Some compilers have been
    499  * even observed to partially fuse the (mod 100) and (mod 400) test,
    500  * but there is an alternative formula that gives the compiler even
    501  * better chances:
    502  *
    503  * (y % 4 == 0) && ((y % 16 == 0) || (y % 25 != 0))
    504  *
    505  * The order of checks is chosen so that the shorcut evaluation can fix
    506  * the result as soon as possible. And the compiler has to do only one
    507  * true division here -- the (mod 4) and (mod 16) can be done with
    508  * direct bit tests. *If* the compiler chooses to do so.
    509  *
    510  * The deduction is as follows: rewrite the standard formula as
    511  *  (y % 4 == 0) && ((y % 4*25 != 0) || (y % 16*25 == 0))
    512  *
    513  * then split the congruences:
    514  *  (y % 4 == 0) && ((y % 4 != 0 || y % 25 != 0) || (y % 16 == 0 && y % 25 == 0))
    515  *
    516  * eliminate the 1st inner term, as it is provably false:
    517  *  (y % 4 == 0) && (y % 25 != 0 || (y % 16 == 0 && y % 25 == 0))
    518  *
    519  * Use the distributive laws on the second major group:
    520  *  (y % 4 == 0) && ((y % 25 != 0 || y % 16 == 0) && (y % 25 != 0 || y % 25 == 0))
    521  *
    522  * Eliminate the constant term, reorder, and voila:
    523  */
    524 
    525 static inline int
    526 is_leapyear(int32_t y) {
    527 	return !(y % 4) && (!(y % 16) || (y % 25));
    528 }
    529 /* The (mod 4) test eliminates 3/4 (or 12/16) of all values.
    530  * The (mod 16) test eliminates another 1/16 of all values.
    531  * 3/16 of all values reach the final division.
    532  * Assuming that the true division is the most costly operation, this
    533  * sequence should give most bang for the buck.
    534  */
    535 
    536 /* misc */
    537 extern int      u32mod7(uint32_t x);
    538 extern int      i32mod7(int32_t x);
    539 extern uint32_t i32fmod(int32_t x, uint32_t d);
    540 
    541 extern int32_t ntpcal_expand_century(uint32_t y, uint32_t m, uint32_t d, uint32_t wd);
    542 
    543 #endif
    544