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
is_leapyear(int32_t y)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