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