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