xref: /netbsd-src/external/bsd/ntp/dist/include/ntp_calendar.h (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: ntp_calendar.h,v 1.7 2018/04/07 00:19:52 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 
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 
35 /* general split representation */
36 typedef struct {
37 	int32_t hi;
38 	int32_t lo;
39 } ntpcal_split;
40 
41 typedef time_t (*systime_func_ptr)(time_t *);
42 
43 /*
44  * set the function for getting the system time. This is mostly used for
45  * unit testing to provide a fixed / shifted time stamp. Setting the
46  * value to NULL restores the original function, that is, 'time()',
47  * which is also the automatic default.
48  */
49 extern systime_func_ptr ntpcal_set_timefunc(systime_func_ptr);
50 
51 /*
52  * days-of-week
53  */
54 #define CAL_SUNDAY	0
55 #define CAL_MONDAY	1
56 #define CAL_TUESDAY	2
57 #define CAL_WEDNESDAY	3
58 #define CAL_THURSDAY	4
59 #define CAL_FRIDAY	5
60 #define CAL_SATURDAY	6
61 #define CAL_SUNDAY7	7	/* also sunday */
62 
63 /*
64  * Days in each month.	30 days hath September...
65  */
66 #define	JAN	31
67 #define	FEB	28
68 #define	FEBLEAP	29
69 #define	MAR	31
70 #define	APR	30
71 #define	MAY	31
72 #define	JUN	30
73 #define	JUL	31
74 #define	AUG	31
75 #define	SEP	30
76 #define	OCT	31
77 #define	NOV	30
78 #define	DEC	31
79 
80 /*
81  * We deal in a 4 year cycle starting at March 1, 1900.	 We assume
82  * we will only want to deal with dates since then, and not to exceed
83  * the rollover day in 2036.
84  */
85 #define	SECSPERMIN	(60)			/* seconds per minute */
86 #define	MINSPERHR	(60)			/* minutes per hour */
87 #define	HRSPERDAY	(24)			/* hours per day */
88 #define	DAYSPERWEEK	(7)			/* days per week */
89 #define	DAYSPERYEAR	(365)			/* days per year */
90 
91 #define	SECSPERHR	(SECSPERMIN * MINSPERHR)
92 #define	SECSPERDAY	(SECSPERHR * HRSPERDAY)
93 #define	SECSPERWEEK	(DAYSPERWEEK * SECSPERDAY)
94 #define	SECSPERYEAR	(365 * SECSPERDAY)	/* regular year */
95 #define	SECSPERLEAPYEAR	(366 * SECSPERDAY)	/* leap year */
96 #define	SECSPERAVGYEAR	31556952		/* mean year length over 400yrs */
97 
98 /*
99  * Gross hacks.	 I have illicit knowlege that there won't be overflows
100  * here, the compiler often can't tell this.
101  */
102 #define	TIMES60(val)	((((val)<<4) - (val))<<2)	/* *(16 - 1) * 4 */
103 #define	TIMES24(val)	(((val)<<4) + ((val)<<3))	/* *16 + *8 */
104 #define	TIMES7(val)	(((val)<<3) - (val))		/* *8  - *1 */
105 #define	TIMESDPERC(val)	(((val)<<10) + ((val)<<8) \
106 			+ ((val)<<7) + ((val)<<5) \
107 			+ ((val)<<4) + ((val)<<2) + (val))	/* *big* hack */
108 
109 
110 extern	const char * const months[12];
111 extern	const char * const daynames[7];
112 
113 extern	void	 caljulian	(uint32_t, struct calendar *);
114 extern	uint32_t caltontp	(const struct calendar *);
115 
116 /*
117  * Convert between 'time_t' and 'vint64'
118  */
119 extern vint64 time_to_vint64(const time_t *);
120 extern time_t vint64_to_time(const vint64 *);
121 
122 /*
123  * Get the build date & time. ATTENTION: The time zone is not specified!
124  * This depends entirely on the C compilers' capabilities to properly
125  * expand the '__TIME__' and '__DATE__' macros, as required by the C
126  * standard.
127  */
128 extern int
129 ntpcal_get_build_date(struct calendar * /* jd */);
130 
131 /*
132  * Convert a timestamp in NTP scale to a time_t value in the UN*X
133  * scale with proper epoch unfolding around a given pivot or the
134  * current system time.
135  */
136 extern vint64
137 ntpcal_ntp_to_time(uint32_t /* ntp */, const time_t * /* pivot */);
138 
139 /*
140  * Convert a timestamp in NTP scale to a 64bit seconds value in the NTP
141  * scale with proper epoch unfolding around a given pivot or the current
142  * system time.
143  * Note: The pivot must be given in UN*X time scale!
144  */
145 extern vint64
146 ntpcal_ntp_to_ntp(uint32_t /* ntp */, const time_t * /* pivot */);
147 
148 /*
149  * Split a time stamp in seconds into elapsed days and elapsed seconds
150  * since midnight.
151  */
152 extern ntpcal_split
153 ntpcal_daysplit(const vint64 *);
154 
155 /*
156  * Merge a number of days and a number of seconds into seconds,
157  * expressed in 64 bits to avoid overflow.
158  */
159 extern vint64
160 ntpcal_dayjoin(int32_t /* days */, int32_t /* seconds */);
161 
162 /* Get the number of leap years since epoch for the number of elapsed
163  * full years
164  */
165 extern int32_t
166 ntpcal_leapyears_in_years(int32_t /* years */);
167 
168 /*
169  * Convert elapsed years in Era into elapsed days in Era.
170  */
171 extern int32_t
172 ntpcal_days_in_years(int32_t /* years */);
173 
174 /*
175  * Convert a number of elapsed month in a year into elapsed days
176  * in year.
177  *
178  * The month will be normalized, and 'res.hi' will contain the
179  * excessive years that must be considered when converting the years,
180  * while 'res.lo' will contain the days since start of the
181  * year. (Expect the resulting days to be negative, with a positive
182  * excess! But then, we need no leap year flag, either...)
183  */
184 extern ntpcal_split
185 ntpcal_days_in_months(int32_t /* months */);
186 
187 /*
188  * Convert ELAPSED years/months/days of gregorian calendar to elapsed
189  * days in Gregorian epoch. No range checks done here!
190  */
191 extern int32_t
192 ntpcal_edate_to_eradays(int32_t /* years */, int32_t /* months */, int32_t /* mdays */);
193 
194 /*
195  * Convert a time spec to seconds. No range checks done here!
196  */
197 extern int32_t
198 ntpcal_etime_to_seconds(int32_t /* hours */, int32_t /* minutes */, int32_t /* seconds */);
199 
200 /*
201  * Convert ELAPSED years/months/days of gregorian calendar to elapsed
202  * days in year.
203  *
204  * Note: This will give the true difference to the start of the given year,
205  * even if months & days are off-scale.
206  */
207 extern int32_t
208 ntpcal_edate_to_yeardays(int32_t /* years */, int32_t /* months */, int32_t /* mdays */);
209 
210 /*
211  * Convert the date part of a 'struct tm' (that is, year, month,
212  * day-of-month) into the RataDie of that day.
213  */
214 extern int32_t
215 ntpcal_tm_to_rd(const struct tm * /* utm */);
216 
217 /*
218  * Convert the date part of a 'struct calendar' (that is, year, month,
219  * day-of-month) into the RataDie of that day.
220  */
221 extern int32_t
222 ntpcal_date_to_rd(const struct calendar * /* jt */);
223 
224 /*
225  * Given the number of elapsed days in the calendar era, split this
226  * number into the number of elapsed years in 'res.quot' and the
227  * number of elapsed days of that year in 'res.rem'.
228  *
229  * if 'isleapyear' is not NULL, it will receive an integer that is 0
230  * for regular years and a non-zero value for leap years.
231  *
232  * The input is limited to [-2^30, 2^30-1]. If the days exceed this
233  * range, errno is set to EDOM and the result is saturated.
234  */
235 extern ntpcal_split
236 ntpcal_split_eradays(int32_t /* days */, int/*BOOL*/ * /* isleapyear */);
237 
238 /*
239  * Given a number of elapsed days in a year and a leap year indicator,
240  * split the number of elapsed days into the number of elapsed months
241  * in 'res.quot' and the number of elapsed days of that month in
242  * 'res.rem'.
243  */
244 extern ntpcal_split
245 ntpcal_split_yeardays(int32_t /* eyd */, int/*BOOL*/ /* isleapyear */);
246 
247 /*
248  * Convert a RataDie number into the date part of a 'struct
249  * calendar'. Return 0 if the year is regular year, !0 if the year is
250  * a leap year.
251  */
252 extern int/*BOOL*/
253 ntpcal_rd_to_date(struct calendar * /* jt */, int32_t /* rd */);
254 
255 /*
256  * Convert a RataDie number into the date part of a 'struct
257  * tm'. Return 0 if the year is regular year, !0 if the year is a leap
258  * year.
259  */
260 extern int/*BOOL*/
261 ntpcal_rd_to_tm(struct tm * /* utm */, int32_t /* rd */);
262 
263 /*
264  * Take a value of seconds since midnight and split it into hhmmss in
265  * a 'struct calendar'. Return excessive days.
266  */
267 extern int32_t
268 ntpcal_daysec_to_date(struct calendar * /* jt */, int32_t /* secs */);
269 
270 /*
271  * Take the time part of a 'struct calendar' and return the seconds
272  * since midnight.
273  */
274 extern int32_t
275 ntpcal_date_to_daysec(const struct calendar *);
276 
277 /*
278  * Take a value of seconds since midnight and split it into hhmmss in
279  * a 'struct tm'. Return excessive days.
280  */
281 extern int32_t
282 ntpcal_daysec_to_tm(struct tm * /* utm */, int32_t /* secs */);
283 
284 extern int32_t
285 ntpcal_tm_to_daysec(const struct tm * /* utm */);
286 
287 /*
288  * convert a year number to rata die of year start
289  */
290 extern int32_t
291 ntpcal_year_to_ystart(int32_t /* year */);
292 
293 /*
294  * For a given RataDie, get the RataDie of the associated year start,
295  * that is, the RataDie of the last January,1st on or before that day.
296  */
297 extern int32_t
298 ntpcal_rd_to_ystart(int32_t /* rd */);
299 
300 /*
301  * convert a RataDie to the RataDie of start of the calendar month.
302  */
303 extern int32_t
304 ntpcal_rd_to_mstart(int32_t /* year */);
305 
306 
307 extern int
308 ntpcal_daysplit_to_date(struct calendar * /* jt */,
309 			const ntpcal_split * /* ds */, int32_t /* dof */);
310 
311 extern int
312 ntpcal_daysplit_to_tm(struct tm * /* utm */, const ntpcal_split * /* ds */,
313 		      int32_t /* dof */);
314 
315 extern int
316 ntpcal_time_to_date(struct calendar * /* jd */, const vint64 * /* ts */);
317 
318 extern int32_t
319 ntpcal_periodic_extend(int32_t /* pivot */, int32_t /* value */,
320 		       int32_t /* cycle */);
321 
322 extern int
323 ntpcal_ntp64_to_date(struct calendar * /* jd */, const vint64 * /* ntp */);
324 
325 extern int
326 ntpcal_ntp_to_date(struct calendar * /* jd */,	uint32_t /* ntp */,
327 		   const time_t * /* pivot */);
328 
329 extern vint64
330 ntpcal_date_to_ntp64(const struct calendar * /* jd */);
331 
332 extern uint32_t
333 ntpcal_date_to_ntp(const struct calendar * /* jd */);
334 
335 extern time_t
336 ntpcal_date_to_time(const struct calendar * /* jd */);
337 
338 /*
339  * ISO week-calendar conversions
340  */
341 extern int32_t
342 isocal_weeks_in_years(int32_t  /* years */);
343 
344 /*
345  * The input is limited to [-2^30, 2^30-1]. If the weeks exceed this
346  * range, errno is set to EDOM and the result is saturated.
347  */
348 extern ntpcal_split
349 isocal_split_eraweeks(int32_t /* weeks */);
350 
351 extern int
352 isocal_ntp64_to_date(struct isodate * /* id */, const vint64 * /* ntp */);
353 
354 extern int
355 isocal_ntp_to_date(struct isodate * /* id */, uint32_t /* ntp */,
356 		   const time_t * /* pivot */);
357 
358 extern vint64
359 isocal_date_to_ntp64(const struct isodate * /* id */);
360 
361 extern uint32_t
362 isocal_date_to_ntp(const struct isodate * /* id */);
363 
364 
365 /*
366  * day-of-week calculations
367  *
368  * Given a RataDie and a day-of-week, calculate a RDN that is reater-than,
369  * greater-or equal, closest, less-or-equal or less-than the given RDN
370  * and denotes the given day-of-week
371  */
372 extern int32_t
373 ntpcal_weekday_gt(int32_t  /* rdn */, int32_t /* dow */);
374 
375 extern int32_t
376 ntpcal_weekday_ge(int32_t /* rdn */, int32_t /* dow */);
377 
378 extern int32_t
379 ntpcal_weekday_close(int32_t /* rdn */, int32_t  /* dow */);
380 
381 extern int32_t
382 ntpcal_weekday_le(int32_t /* rdn */, int32_t /* dow */);
383 
384 extern int32_t
385 ntpcal_weekday_lt(int32_t /* rdn */, int32_t /* dow */);
386 
387 
388 /*
389  * handling of base date spec
390  */
391 extern int32_t
392 basedate_eval_buildstamp(void);
393 
394 extern int32_t
395 basedate_eval_string(const char *str);
396 
397 extern int32_t
398 basedate_set_day(int32_t dayno);
399 
400 extern uint32_t
401 basedate_get_day(void);
402 
403 extern time_t
404 basedate_get_eracenter(void);
405 
406 extern time_t
407 basedate_get_erabase(void);
408 
409 
410 /*
411  * Additional support stuff for Ed Rheingold's calendrical calculations
412  */
413 
414 /*
415  * Start day of NTP time as days past the imaginary date 12/1/1 BC.
416  * (This is the beginning of the Christian Era, or BCE.)
417  */
418 #define	DAY_NTP_STARTS 693596
419 
420 /*
421  * Start day of the UNIX epoch. This is the Rata Die of 1970-01-01.
422  */
423 #define DAY_UNIX_STARTS 719163
424 
425 /*
426  * Difference between UN*X and NTP epoch (25567).
427  */
428 #define NTP_TO_UNIX_DAYS (DAY_UNIX_STARTS - DAY_NTP_STARTS)
429 
430 /*
431  * Days in a normal 4 year leap year calendar cycle (1461).
432  */
433 #define	GREGORIAN_NORMAL_LEAP_CYCLE_DAYS	(3 * 365 + 366)
434 
435 /*
436  * Days in a normal 100 year leap year calendar (36524).  We lose a
437  * leap day in years evenly divisible by 100 but not by 400.
438  */
439 #define	GREGORIAN_NORMAL_CENTURY_DAYS	\
440 			(25 * GREGORIAN_NORMAL_LEAP_CYCLE_DAYS - 1)
441 
442 /*
443  * The Gregorian calendar is based on a 400 year cycle. This is the
444  * number of days in each cycle (146097).  We gain a leap day in years
445  * divisible by 400 relative to the "normal" century.
446  */
447 #define	GREGORIAN_CYCLE_DAYS (4 * GREGORIAN_NORMAL_CENTURY_DAYS + 1)
448 
449 /*
450  * Number of weeks in 400 years (20871).
451  */
452 #define	GREGORIAN_CYCLE_WEEKS (GREGORIAN_CYCLE_DAYS / 7)
453 
454 #define	is_leapyear(y)	(!((y) % 4) && !(!((y) % 100) && (y) % 400))
455 
456 #endif
457