xref: /netbsd-src/external/bsd/ntp/dist/include/ntp_calendar.h (revision cdfa2a7ef92791ba9db70a584a1d904730e6fb46)
1*cdfa2a7eSchristos /*	$NetBSD: ntp_calendar.h,v 1.8 2020/05/25 20:47:19 christos Exp $	*/
2abb0f93cSkardel 
3abb0f93cSkardel /*
4abb0f93cSkardel  * ntp_calendar.h - definitions for the calendar time-of-day routine
5abb0f93cSkardel  */
6abb0f93cSkardel #ifndef NTP_CALENDAR_H
7abb0f93cSkardel #define NTP_CALENDAR_H
8abb0f93cSkardel 
98585484eSchristos #include <time.h>
108585484eSchristos 
11abb0f93cSkardel #include "ntp_types.h"
12abb0f93cSkardel 
138585484eSchristos /* gregorian calendar date */
14abb0f93cSkardel struct calendar {
158585484eSchristos 	uint16_t year;		/* year (A.D.) */
168585484eSchristos 	uint16_t yearday;	/* day of year, 1 = January 1 */
178585484eSchristos 	uint8_t  month;		/* month, 1 = January */
188585484eSchristos 	uint8_t  monthday;	/* day of month */
198585484eSchristos 	uint8_t  hour;		/* hour of day, midnight = 0 */
208585484eSchristos 	uint8_t  minute;	/* minute of hour */
218585484eSchristos 	uint8_t  second;	/* second of minute */
228585484eSchristos 	uint8_t  weekday;	/* 0..7, 0=Sunday */
23abb0f93cSkardel };
24*cdfa2a7eSchristos typedef struct calendar TCivilDate;
25*cdfa2a7eSchristos typedef struct calendar const TcCivilDate;
26abb0f93cSkardel 
278585484eSchristos /* ISO week calendar date */
288585484eSchristos struct isodate {
298585484eSchristos 	uint16_t year;		/* year (A.D.) */
308585484eSchristos 	uint8_t	 week;		/* 1..53, week in year */
318585484eSchristos 	uint8_t	 weekday;	/* 1..7, 1=Monday */
328585484eSchristos 	uint8_t	 hour;		/* hour of day, midnight = 0 */
338585484eSchristos 	uint8_t	 minute;	/* minute of hour */
348585484eSchristos 	uint8_t	 second;	/* second of minute */
358585484eSchristos };
36*cdfa2a7eSchristos typedef struct isodate TIsoDate;
37*cdfa2a7eSchristos typedef struct isodate const TcIsoDate;
388585484eSchristos 
398585484eSchristos /* general split representation */
408585484eSchristos typedef struct {
418585484eSchristos 	int32_t hi;
428585484eSchristos 	int32_t lo;
438585484eSchristos } ntpcal_split;
448585484eSchristos 
458585484eSchristos typedef time_t (*systime_func_ptr)(time_t *);
468585484eSchristos 
478585484eSchristos /*
488585484eSchristos  * set the function for getting the system time. This is mostly used for
498585484eSchristos  * unit testing to provide a fixed / shifted time stamp. Setting the
508585484eSchristos  * value to NULL restores the original function, that is, 'time()',
518585484eSchristos  * which is also the automatic default.
528585484eSchristos  */
538585484eSchristos extern systime_func_ptr ntpcal_set_timefunc(systime_func_ptr);
548585484eSchristos 
558585484eSchristos /*
568585484eSchristos  * days-of-week
578585484eSchristos  */
588585484eSchristos #define CAL_SUNDAY	0
598585484eSchristos #define CAL_MONDAY	1
608585484eSchristos #define CAL_TUESDAY	2
618585484eSchristos #define CAL_WEDNESDAY	3
628585484eSchristos #define CAL_THURSDAY	4
638585484eSchristos #define CAL_FRIDAY	5
648585484eSchristos #define CAL_SATURDAY	6
658585484eSchristos #define CAL_SUNDAY7	7	/* also sunday */
668585484eSchristos 
67abb0f93cSkardel /*
68abb0f93cSkardel  * Days in each month.	30 days hath September...
69abb0f93cSkardel  */
70abb0f93cSkardel #define	JAN	31
71abb0f93cSkardel #define	FEB	28
72abb0f93cSkardel #define	FEBLEAP	29
73abb0f93cSkardel #define	MAR	31
74abb0f93cSkardel #define	APR	30
75abb0f93cSkardel #define	MAY	31
76abb0f93cSkardel #define	JUN	30
77abb0f93cSkardel #define	JUL	31
78abb0f93cSkardel #define	AUG	31
79abb0f93cSkardel #define	SEP	30
80abb0f93cSkardel #define	OCT	31
81abb0f93cSkardel #define	NOV	30
82abb0f93cSkardel #define	DEC	31
83abb0f93cSkardel 
84abb0f93cSkardel /*
85abb0f93cSkardel  * We deal in a 4 year cycle starting at March 1, 1900.	 We assume
86abb0f93cSkardel  * we will only want to deal with dates since then, and not to exceed
87abb0f93cSkardel  * the rollover day in 2036.
88abb0f93cSkardel  */
89abb0f93cSkardel #define	SECSPERMIN	(60)			/* seconds per minute */
90abb0f93cSkardel #define	MINSPERHR	(60)			/* minutes per hour */
91abb0f93cSkardel #define	HRSPERDAY	(24)			/* hours per day */
927476e6e4Schristos #define	DAYSPERWEEK	(7)			/* days per week */
93abb0f93cSkardel #define	DAYSPERYEAR	(365)			/* days per year */
94abb0f93cSkardel 
958585484eSchristos #define	SECSPERHR	(SECSPERMIN * MINSPERHR)
968585484eSchristos #define	SECSPERDAY	(SECSPERHR * HRSPERDAY)
977476e6e4Schristos #define	SECSPERWEEK	(DAYSPERWEEK * SECSPERDAY)
98abb0f93cSkardel #define	SECSPERYEAR	(365 * SECSPERDAY)	/* regular year */
99abb0f93cSkardel #define	SECSPERLEAPYEAR	(366 * SECSPERDAY)	/* leap year */
1008585484eSchristos #define	SECSPERAVGYEAR	31556952		/* mean year length over 400yrs */
101abb0f93cSkardel 
102*cdfa2a7eSchristos #define GPSWEEKS	1024			/* GPS week cycle */
103abb0f93cSkardel /*
104abb0f93cSkardel  * Gross hacks.	 I have illicit knowlege that there won't be overflows
105abb0f93cSkardel  * here, the compiler often can't tell this.
106abb0f93cSkardel  */
107abb0f93cSkardel #define	TIMES60(val)	((((val)<<4) - (val))<<2)	/* *(16 - 1) * 4 */
108abb0f93cSkardel #define	TIMES24(val)	(((val)<<4) + ((val)<<3))	/* *16 + *8 */
109abb0f93cSkardel #define	TIMES7(val)	(((val)<<3) - (val))		/* *8  - *1 */
110abb0f93cSkardel #define	TIMESDPERC(val)	(((val)<<10) + ((val)<<8) \
111abb0f93cSkardel 			+ ((val)<<7) + ((val)<<5) \
112abb0f93cSkardel 			+ ((val)<<4) + ((val)<<2) + (val))	/* *big* hack */
113abb0f93cSkardel 
1148585484eSchristos 
1158585484eSchristos extern	const char * const months[12];
1168585484eSchristos extern	const char * const daynames[7];
1178585484eSchristos 
118*cdfa2a7eSchristos extern	char *	 ntpcal_iso8601std(char*, size_t, struct calendar const*);
1198585484eSchristos extern	void	 caljulian	(uint32_t, struct calendar *);
1208585484eSchristos extern	uint32_t caltontp	(const struct calendar *);
121abb0f93cSkardel 
122abb0f93cSkardel /*
1238585484eSchristos  * Convert between 'time_t' and 'vint64'
124abb0f93cSkardel  */
1258585484eSchristos extern vint64 time_to_vint64(const time_t *);
1268585484eSchristos extern time_t vint64_to_time(const vint64 *);
1278585484eSchristos 
1288585484eSchristos /*
1298585484eSchristos  * Get the build date & time. ATTENTION: The time zone is not specified!
1308585484eSchristos  * This depends entirely on the C compilers' capabilities to properly
1318585484eSchristos  * expand the '__TIME__' and '__DATE__' macros, as required by the C
1328585484eSchristos  * standard.
1338585484eSchristos  */
1348585484eSchristos extern int
135b8ecfcfeSchristos ntpcal_get_build_date(struct calendar * /* jd */);
1368585484eSchristos 
1378585484eSchristos /*
1388585484eSchristos  * Convert a timestamp in NTP scale to a time_t value in the UN*X
1398585484eSchristos  * scale with proper epoch unfolding around a given pivot or the
1408585484eSchristos  * current system time.
1418585484eSchristos  */
1428585484eSchristos extern vint64
143b8ecfcfeSchristos ntpcal_ntp_to_time(uint32_t /* ntp */, const time_t * /* pivot */);
1448585484eSchristos 
1458585484eSchristos /*
1468585484eSchristos  * Convert a timestamp in NTP scale to a 64bit seconds value in the NTP
1478585484eSchristos  * scale with proper epoch unfolding around a given pivot or the current
1488585484eSchristos  * system time.
1498585484eSchristos  * Note: The pivot must be given in UN*X time scale!
1508585484eSchristos  */
1518585484eSchristos extern vint64
152b8ecfcfeSchristos ntpcal_ntp_to_ntp(uint32_t /* ntp */, const time_t * /* pivot */);
1538585484eSchristos 
1548585484eSchristos /*
1558585484eSchristos  * Split a time stamp in seconds into elapsed days and elapsed seconds
1568585484eSchristos  * since midnight.
1578585484eSchristos  */
1588585484eSchristos extern ntpcal_split
1598585484eSchristos ntpcal_daysplit(const vint64 *);
1608585484eSchristos 
1618585484eSchristos /*
162*cdfa2a7eSchristos  * Split a time stamp in seconds into elapsed weeks and elapsed seconds
163*cdfa2a7eSchristos  * since start of week.
164*cdfa2a7eSchristos  */
165*cdfa2a7eSchristos extern ntpcal_split
166*cdfa2a7eSchristos ntpcal_weeksplit(const vint64 *);
167*cdfa2a7eSchristos 
168*cdfa2a7eSchristos /*
1698585484eSchristos  * Merge a number of days and a number of seconds into seconds,
1708585484eSchristos  * expressed in 64 bits to avoid overflow.
1718585484eSchristos  */
1728585484eSchristos extern vint64
173b8ecfcfeSchristos ntpcal_dayjoin(int32_t /* days */, int32_t /* seconds */);
1748585484eSchristos 
175*cdfa2a7eSchristos /*
176*cdfa2a7eSchristos  * Merge a number of weeks and a number of seconds into seconds,
177*cdfa2a7eSchristos  * expressed in 64 bits to avoid overflow.
178*cdfa2a7eSchristos  */
179*cdfa2a7eSchristos extern vint64
180*cdfa2a7eSchristos ntpcal_weekjoin(int32_t /* weeks */, int32_t /* seconds */);
181*cdfa2a7eSchristos 
182af12ab5eSchristos /* Get the number of leap years since epoch for the number of elapsed
183af12ab5eSchristos  * full years
184af12ab5eSchristos  */
185af12ab5eSchristos extern int32_t
186af12ab5eSchristos ntpcal_leapyears_in_years(int32_t /* years */);
187af12ab5eSchristos 
1888585484eSchristos /*
1898585484eSchristos  * Convert elapsed years in Era into elapsed days in Era.
1908585484eSchristos  */
1918585484eSchristos extern int32_t
192b8ecfcfeSchristos ntpcal_days_in_years(int32_t /* years */);
1938585484eSchristos 
1948585484eSchristos /*
1958585484eSchristos  * Convert a number of elapsed month in a year into elapsed days
1968585484eSchristos  * in year.
1978585484eSchristos  *
1988585484eSchristos  * The month will be normalized, and 'res.hi' will contain the
1998585484eSchristos  * excessive years that must be considered when converting the years,
2008585484eSchristos  * while 'res.lo' will contain the days since start of the
2018585484eSchristos  * year. (Expect the resulting days to be negative, with a positive
2028585484eSchristos  * excess! But then, we need no leap year flag, either...)
2038585484eSchristos  */
2048585484eSchristos extern ntpcal_split
205b8ecfcfeSchristos ntpcal_days_in_months(int32_t /* months */);
2068585484eSchristos 
2078585484eSchristos /*
2088585484eSchristos  * Convert ELAPSED years/months/days of gregorian calendar to elapsed
2098585484eSchristos  * days in Gregorian epoch. No range checks done here!
2108585484eSchristos  */
2118585484eSchristos extern int32_t
212b8ecfcfeSchristos ntpcal_edate_to_eradays(int32_t /* years */, int32_t /* months */, int32_t /* mdays */);
2138585484eSchristos 
2148585484eSchristos /*
2158585484eSchristos  * Convert a time spec to seconds. No range checks done here!
2168585484eSchristos  */
2178585484eSchristos extern int32_t
218b8ecfcfeSchristos ntpcal_etime_to_seconds(int32_t /* hours */, int32_t /* minutes */, int32_t /* seconds */);
2198585484eSchristos 
2208585484eSchristos /*
2218585484eSchristos  * Convert ELAPSED years/months/days of gregorian calendar to elapsed
2228585484eSchristos  * days in year.
2238585484eSchristos  *
2248585484eSchristos  * Note: This will give the true difference to the start of the given year,
2258585484eSchristos  * even if months & days are off-scale.
2268585484eSchristos  */
2278585484eSchristos extern int32_t
228b8ecfcfeSchristos ntpcal_edate_to_yeardays(int32_t /* years */, int32_t /* months */, int32_t /* mdays */);
2298585484eSchristos 
2308585484eSchristos /*
2318585484eSchristos  * Convert the date part of a 'struct tm' (that is, year, month,
2328585484eSchristos  * day-of-month) into the RataDie of that day.
2338585484eSchristos  */
2348585484eSchristos extern int32_t
235b8ecfcfeSchristos ntpcal_tm_to_rd(const struct tm * /* utm */);
2368585484eSchristos 
2378585484eSchristos /*
2388585484eSchristos  * Convert the date part of a 'struct calendar' (that is, year, month,
2398585484eSchristos  * day-of-month) into the RataDie of that day.
2408585484eSchristos  */
2418585484eSchristos extern int32_t
242b8ecfcfeSchristos ntpcal_date_to_rd(const struct calendar * /* jt */);
2438585484eSchristos 
2448585484eSchristos /*
2458585484eSchristos  * Given the number of elapsed days in the calendar era, split this
2468585484eSchristos  * number into the number of elapsed years in 'res.quot' and the
2478585484eSchristos  * number of elapsed days of that year in 'res.rem'.
2488585484eSchristos  *
2498585484eSchristos  * if 'isleapyear' is not NULL, it will receive an integer that is 0
2508585484eSchristos  * for regular years and a non-zero value for leap years.
251af12ab5eSchristos  *
252af12ab5eSchristos  * The input is limited to [-2^30, 2^30-1]. If the days exceed this
253af12ab5eSchristos  * range, errno is set to EDOM and the result is saturated.
2548585484eSchristos  */
2558585484eSchristos extern ntpcal_split
256b8ecfcfeSchristos ntpcal_split_eradays(int32_t /* days */, int/*BOOL*/ * /* isleapyear */);
2578585484eSchristos 
2588585484eSchristos /*
2598585484eSchristos  * Given a number of elapsed days in a year and a leap year indicator,
2608585484eSchristos  * split the number of elapsed days into the number of elapsed months
2618585484eSchristos  * in 'res.quot' and the number of elapsed days of that month in
2628585484eSchristos  * 'res.rem'.
2638585484eSchristos  */
2648585484eSchristos extern ntpcal_split
265b8ecfcfeSchristos ntpcal_split_yeardays(int32_t /* eyd */, int/*BOOL*/ /* isleapyear */);
2668585484eSchristos 
2678585484eSchristos /*
2688585484eSchristos  * Convert a RataDie number into the date part of a 'struct
2698585484eSchristos  * calendar'. Return 0 if the year is regular year, !0 if the year is
2708585484eSchristos  * a leap year.
2718585484eSchristos  */
2728585484eSchristos extern int/*BOOL*/
273b8ecfcfeSchristos ntpcal_rd_to_date(struct calendar * /* jt */, int32_t /* rd */);
2748585484eSchristos 
2758585484eSchristos /*
2768585484eSchristos  * Convert a RataDie number into the date part of a 'struct
2778585484eSchristos  * tm'. Return 0 if the year is regular year, !0 if the year is a leap
2788585484eSchristos  * year.
2798585484eSchristos  */
2808585484eSchristos extern int/*BOOL*/
281b8ecfcfeSchristos ntpcal_rd_to_tm(struct tm * /* utm */, int32_t /* rd */);
2828585484eSchristos 
2838585484eSchristos /*
2848585484eSchristos  * Take a value of seconds since midnight and split it into hhmmss in
2858585484eSchristos  * a 'struct calendar'. Return excessive days.
2868585484eSchristos  */
2878585484eSchristos extern int32_t
288b8ecfcfeSchristos ntpcal_daysec_to_date(struct calendar * /* jt */, int32_t /* secs */);
2898585484eSchristos 
2908585484eSchristos /*
2918585484eSchristos  * Take the time part of a 'struct calendar' and return the seconds
2928585484eSchristos  * since midnight.
2938585484eSchristos  */
2948585484eSchristos extern int32_t
2958585484eSchristos ntpcal_date_to_daysec(const struct calendar *);
2968585484eSchristos 
2978585484eSchristos /*
2988585484eSchristos  * Take a value of seconds since midnight and split it into hhmmss in
2998585484eSchristos  * a 'struct tm'. Return excessive days.
3008585484eSchristos  */
3018585484eSchristos extern int32_t
302b8ecfcfeSchristos ntpcal_daysec_to_tm(struct tm * /* utm */, int32_t /* secs */);
3038585484eSchristos 
3048585484eSchristos extern int32_t
305b8ecfcfeSchristos ntpcal_tm_to_daysec(const struct tm * /* utm */);
3068585484eSchristos 
3078585484eSchristos /*
3088585484eSchristos  * convert a year number to rata die of year start
3098585484eSchristos  */
3108585484eSchristos extern int32_t
311b8ecfcfeSchristos ntpcal_year_to_ystart(int32_t /* year */);
3128585484eSchristos 
3138585484eSchristos /*
3148585484eSchristos  * For a given RataDie, get the RataDie of the associated year start,
3158585484eSchristos  * that is, the RataDie of the last January,1st on or before that day.
3168585484eSchristos  */
3178585484eSchristos extern int32_t
318b8ecfcfeSchristos ntpcal_rd_to_ystart(int32_t /* rd */);
3198585484eSchristos 
3208585484eSchristos /*
3218585484eSchristos  * convert a RataDie to the RataDie of start of the calendar month.
3228585484eSchristos  */
3238585484eSchristos extern int32_t
324b8ecfcfeSchristos ntpcal_rd_to_mstart(int32_t /* year */);
325abb0f93cSkardel 
326abb0f93cSkardel 
3278585484eSchristos extern int
328b8ecfcfeSchristos ntpcal_daysplit_to_date(struct calendar * /* jt */,
329b8ecfcfeSchristos 			const ntpcal_split * /* ds */, int32_t /* dof */);
3308585484eSchristos 
3318585484eSchristos extern int
332b8ecfcfeSchristos ntpcal_daysplit_to_tm(struct tm * /* utm */, const ntpcal_split * /* ds */,
333b8ecfcfeSchristos 		      int32_t /* dof */);
3348585484eSchristos 
3358585484eSchristos extern int
336b8ecfcfeSchristos ntpcal_time_to_date(struct calendar * /* jd */, const vint64 * /* ts */);
3378585484eSchristos 
3388585484eSchristos extern int32_t
339b8ecfcfeSchristos ntpcal_periodic_extend(int32_t /* pivot */, int32_t /* value */,
340b8ecfcfeSchristos 		       int32_t /* cycle */);
3418585484eSchristos 
3428585484eSchristos extern int
343b8ecfcfeSchristos ntpcal_ntp64_to_date(struct calendar * /* jd */, const vint64 * /* ntp */);
344b8ecfcfeSchristos 
345b8ecfcfeSchristos extern int
346b8ecfcfeSchristos ntpcal_ntp_to_date(struct calendar * /* jd */,	uint32_t /* ntp */,
347b8ecfcfeSchristos 		   const time_t * /* pivot */);
348b8ecfcfeSchristos 
349b8ecfcfeSchristos extern vint64
350b8ecfcfeSchristos ntpcal_date_to_ntp64(const struct calendar * /* jd */);
3518585484eSchristos 
3528585484eSchristos extern uint32_t
353b8ecfcfeSchristos ntpcal_date_to_ntp(const struct calendar * /* jd */);
3548585484eSchristos 
3558585484eSchristos extern time_t
356b8ecfcfeSchristos ntpcal_date_to_time(const struct calendar * /* jd */);
3578585484eSchristos 
3588585484eSchristos /*
3598585484eSchristos  * ISO week-calendar conversions
3608585484eSchristos  */
3618585484eSchristos extern int32_t
362b8ecfcfeSchristos isocal_weeks_in_years(int32_t  /* years */);
3638585484eSchristos 
364af12ab5eSchristos /*
365af12ab5eSchristos  * The input is limited to [-2^30, 2^30-1]. If the weeks exceed this
366af12ab5eSchristos  * range, errno is set to EDOM and the result is saturated.
367af12ab5eSchristos  */
3688585484eSchristos extern ntpcal_split
369b8ecfcfeSchristos isocal_split_eraweeks(int32_t /* weeks */);
3708585484eSchristos 
3718585484eSchristos extern int
372b8ecfcfeSchristos isocal_ntp64_to_date(struct isodate * /* id */, const vint64 * /* ntp */);
373b8ecfcfeSchristos 
374b8ecfcfeSchristos extern int
375b8ecfcfeSchristos isocal_ntp_to_date(struct isodate * /* id */, uint32_t /* ntp */,
376b8ecfcfeSchristos 		   const time_t * /* pivot */);
377b8ecfcfeSchristos 
378b8ecfcfeSchristos extern vint64
379b8ecfcfeSchristos isocal_date_to_ntp64(const struct isodate * /* id */);
3808585484eSchristos 
3818585484eSchristos extern uint32_t
382b8ecfcfeSchristos isocal_date_to_ntp(const struct isodate * /* id */);
3838585484eSchristos 
3848585484eSchristos 
3858585484eSchristos /*
3868585484eSchristos  * day-of-week calculations
3878585484eSchristos  *
3888585484eSchristos  * Given a RataDie and a day-of-week, calculate a RDN that is reater-than,
3898585484eSchristos  * greater-or equal, closest, less-or-equal or less-than the given RDN
3908585484eSchristos  * and denotes the given day-of-week
3918585484eSchristos  */
3928585484eSchristos extern int32_t
393b8ecfcfeSchristos ntpcal_weekday_gt(int32_t  /* rdn */, int32_t /* dow */);
3948585484eSchristos 
3958585484eSchristos extern int32_t
396b8ecfcfeSchristos ntpcal_weekday_ge(int32_t /* rdn */, int32_t /* dow */);
3978585484eSchristos 
3988585484eSchristos extern int32_t
399b8ecfcfeSchristos ntpcal_weekday_close(int32_t /* rdn */, int32_t  /* dow */);
4008585484eSchristos 
4018585484eSchristos extern int32_t
402b8ecfcfeSchristos ntpcal_weekday_le(int32_t /* rdn */, int32_t /* dow */);
4038585484eSchristos 
4048585484eSchristos extern int32_t
405b8ecfcfeSchristos ntpcal_weekday_lt(int32_t /* rdn */, int32_t /* dow */);
406abb0f93cSkardel 
4074eea345dSchristos 
4084eea345dSchristos /*
4094eea345dSchristos  * handling of base date spec
4104eea345dSchristos  */
4114eea345dSchristos extern int32_t
4124eea345dSchristos basedate_eval_buildstamp(void);
4134eea345dSchristos 
4144eea345dSchristos extern int32_t
4154eea345dSchristos basedate_eval_string(const char *str);
4164eea345dSchristos 
4174eea345dSchristos extern int32_t
4184eea345dSchristos basedate_set_day(int32_t dayno);
4194eea345dSchristos 
4204eea345dSchristos extern uint32_t
4214eea345dSchristos basedate_get_day(void);
4224eea345dSchristos 
4234eea345dSchristos extern time_t
4244eea345dSchristos basedate_get_eracenter(void);
4254eea345dSchristos 
4264eea345dSchristos extern time_t
4274eea345dSchristos basedate_get_erabase(void);
4284eea345dSchristos 
429*cdfa2a7eSchristos extern uint32_t
430*cdfa2a7eSchristos basedate_get_gpsweek(void);
431*cdfa2a7eSchristos 
432*cdfa2a7eSchristos extern uint32_t
433*cdfa2a7eSchristos basedate_expand_gpsweek(unsigned short weekno);
4344eea345dSchristos 
435abb0f93cSkardel /*
436abb0f93cSkardel  * Additional support stuff for Ed Rheingold's calendrical calculations
437abb0f93cSkardel  */
438abb0f93cSkardel 
439abb0f93cSkardel /*
440*cdfa2a7eSchristos  * Start day of NTP time as days past 0000-12-31 in the proleptic
441*cdfa2a7eSchristos  * Gregorian calendar. (So 0001-01-01 is day number 1; this is the Rata
442*cdfa2a7eSchristos  * Die counting scheme used by Ed Rheingold in his book "Calendrical
443*cdfa2a7eSchristos  * Calculations".)
444abb0f93cSkardel  */
445abb0f93cSkardel #define	DAY_NTP_STARTS 693596
446abb0f93cSkardel 
447abb0f93cSkardel /*
4488585484eSchristos  * Start day of the UNIX epoch. This is the Rata Die of 1970-01-01.
449abb0f93cSkardel  */
4508585484eSchristos #define DAY_UNIX_STARTS 719163
451abb0f93cSkardel 
452abb0f93cSkardel /*
453*cdfa2a7eSchristos  * Start day of the GPS epoch. This is the Rata Die of 1980-01-06
454*cdfa2a7eSchristos  */
455*cdfa2a7eSchristos #define DAY_GPS_STARTS 722820
456*cdfa2a7eSchristos 
457*cdfa2a7eSchristos /*
4588585484eSchristos  * Difference between UN*X and NTP epoch (25567).
459abb0f93cSkardel  */
4608585484eSchristos #define NTP_TO_UNIX_DAYS (DAY_UNIX_STARTS - DAY_NTP_STARTS)
4618585484eSchristos 
4628585484eSchristos /*
463*cdfa2a7eSchristos  * Difference between GPS and NTP epoch (29224)
464*cdfa2a7eSchristos  */
465*cdfa2a7eSchristos #define NTP_TO_GPS_DAYS (DAY_GPS_STARTS - DAY_NTP_STARTS)
466*cdfa2a7eSchristos 
467*cdfa2a7eSchristos /*
4688585484eSchristos  * Days in a normal 4 year leap year calendar cycle (1461).
4698585484eSchristos  */
470*cdfa2a7eSchristos #define	GREGORIAN_NORMAL_LEAP_CYCLE_DAYS	(4 * 365 + 1)
4718585484eSchristos 
4728585484eSchristos /*
4738585484eSchristos  * Days in a normal 100 year leap year calendar (36524).  We lose a
4748585484eSchristos  * leap day in years evenly divisible by 100 but not by 400.
4758585484eSchristos  */
4768585484eSchristos #define	GREGORIAN_NORMAL_CENTURY_DAYS	\
4778585484eSchristos 			(25 * GREGORIAN_NORMAL_LEAP_CYCLE_DAYS - 1)
4788585484eSchristos 
4798585484eSchristos /*
4808585484eSchristos  * The Gregorian calendar is based on a 400 year cycle. This is the
4818585484eSchristos  * number of days in each cycle (146097).  We gain a leap day in years
4828585484eSchristos  * divisible by 400 relative to the "normal" century.
4838585484eSchristos  */
4848585484eSchristos #define	GREGORIAN_CYCLE_DAYS (4 * GREGORIAN_NORMAL_CENTURY_DAYS + 1)
4858585484eSchristos 
4868585484eSchristos /*
4878585484eSchristos  * Number of weeks in 400 years (20871).
4888585484eSchristos  */
4898585484eSchristos #define	GREGORIAN_CYCLE_WEEKS (GREGORIAN_CYCLE_DAYS / 7)
490abb0f93cSkardel 
491*cdfa2a7eSchristos /*
492*cdfa2a7eSchristos  * Is a Greogorian calendar year a leap year? The obvious solution is to
493*cdfa2a7eSchristos  * test the expression
494*cdfa2a7eSchristos  *
495*cdfa2a7eSchristos  * (y % 4 == 0) && ((y % 100 != 0) || (y % 400 == 0))
496*cdfa2a7eSchristos  *
497*cdfa2a7eSchristos  * This needs (in theory) 2 true divisions -- most compilers check the
498*cdfa2a7eSchristos  * (mod 4) condition by doing a bit test. Some compilers have been
499*cdfa2a7eSchristos  * even observed to partially fuse the (mod 100) and (mod 400) test,
500*cdfa2a7eSchristos  * but there is an alternative formula that gives the compiler even
501*cdfa2a7eSchristos  * better chances:
502*cdfa2a7eSchristos  *
503*cdfa2a7eSchristos  * (y % 4 == 0) && ((y % 16 == 0) || (y % 25 != 0))
504*cdfa2a7eSchristos  *
505*cdfa2a7eSchristos  * The order of checks is chosen so that the shorcut evaluation can fix
506*cdfa2a7eSchristos  * the result as soon as possible. And the compiler has to do only one
507*cdfa2a7eSchristos  * true division here -- the (mod 4) and (mod 16) can be done with
508*cdfa2a7eSchristos  * direct bit tests. *If* the compiler chooses to do so.
509*cdfa2a7eSchristos  *
510*cdfa2a7eSchristos  * The deduction is as follows: rewrite the standard formula as
511*cdfa2a7eSchristos  *  (y % 4 == 0) && ((y % 4*25 != 0) || (y % 16*25 == 0))
512*cdfa2a7eSchristos  *
513*cdfa2a7eSchristos  * then split the congruences:
514*cdfa2a7eSchristos  *  (y % 4 == 0) && ((y % 4 != 0 || y % 25 != 0) || (y % 16 == 0 && y % 25 == 0))
515*cdfa2a7eSchristos  *
516*cdfa2a7eSchristos  * eliminate the 1st inner term, as it is provably false:
517*cdfa2a7eSchristos  *  (y % 4 == 0) && (y % 25 != 0 || (y % 16 == 0 && y % 25 == 0))
518*cdfa2a7eSchristos  *
519*cdfa2a7eSchristos  * Use the distributive laws on the second major group:
520*cdfa2a7eSchristos  *  (y % 4 == 0) && ((y % 25 != 0 || y % 16 == 0) && (y % 25 != 0 || y % 25 == 0))
521*cdfa2a7eSchristos  *
522*cdfa2a7eSchristos  * Eliminate the constant term, reorder, and voila:
523*cdfa2a7eSchristos  */
524*cdfa2a7eSchristos 
525*cdfa2a7eSchristos static inline int
is_leapyear(int32_t y)526*cdfa2a7eSchristos is_leapyear(int32_t y) {
527*cdfa2a7eSchristos 	return !(y % 4) && (!(y % 16) || (y % 25));
528*cdfa2a7eSchristos }
529*cdfa2a7eSchristos /* The (mod 4) test eliminates 3/4 (or 12/16) of all values.
530*cdfa2a7eSchristos  * The (mod 16) test eliminates another 1/16 of all values.
531*cdfa2a7eSchristos  * 3/16 of all values reach the final division.
532*cdfa2a7eSchristos  * Assuming that the true division is the most costly operation, this
533*cdfa2a7eSchristos  * sequence should give most bang for the buck.
534*cdfa2a7eSchristos  */
535*cdfa2a7eSchristos 
536*cdfa2a7eSchristos /* misc */
537*cdfa2a7eSchristos extern int      u32mod7(uint32_t x);
538*cdfa2a7eSchristos extern int      i32mod7(int32_t x);
539*cdfa2a7eSchristos extern uint32_t i32fmod(int32_t x, uint32_t d);
540*cdfa2a7eSchristos 
541*cdfa2a7eSchristos extern int32_t ntpcal_expand_century(uint32_t y, uint32_t m, uint32_t d, uint32_t wd);
542abb0f93cSkardel 
543abb0f93cSkardel #endif
544