ntp_calendar.h revision 358659
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 */
12struct 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};
22typedef struct calendar TCivilDate;
23typedef struct calendar const TcCivilDate;
24
25/* ISO week calendar date */
26struct 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};
34typedef struct isodate TIsoDate;
35typedef struct isodate const TcIsoDate;
36
37/* general split representation */
38typedef struct {
39	int32_t hi;
40	int32_t lo;
41} ntpcal_split;
42
43typedef 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 */
51extern 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
113extern	const char * const months[12];
114extern	const char * const daynames[7];
115
116extern	char *	 ntpcal_iso8601std(char*, size_t, struct calendar const*);
117extern	void	 caljulian	(uint32_t, struct calendar *);
118extern	uint32_t caltontp	(const struct calendar *);
119
120/*
121 * Convert between 'time_t' and 'vint64'
122 */
123extern vint64 time_to_vint64(const time_t *);
124extern 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 */
132extern int
133ntpcal_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 */
140extern vint64
141ntpcal_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 */
149extern vint64
150ntpcal_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 */
156extern ntpcal_split
157ntpcal_daysplit(const vint64 *);
158
159/*
160 * Split a time stamp in seconds into elapsed weeks and elapsed seconds
161 * since start of week.
162 */
163extern ntpcal_split
164ntpcal_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 */
170extern vint64
171ntpcal_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 */
177extern vint64
178ntpcal_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 */
183extern int32_t
184ntpcal_leapyears_in_years(int32_t /* years */);
185
186/*
187 * Convert elapsed years in Era into elapsed days in Era.
188 */
189extern int32_t
190ntpcal_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 */
202extern ntpcal_split
203ntpcal_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 */
209extern int32_t
210ntpcal_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 */
215extern int32_t
216ntpcal_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 */
225extern int32_t
226ntpcal_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 */
232extern int32_t
233ntpcal_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 */
239extern int32_t
240ntpcal_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 */
253extern ntpcal_split
254ntpcal_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 */
262extern ntpcal_split
263ntpcal_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 */
270extern int/*BOOL*/
271ntpcal_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 */
278extern int/*BOOL*/
279ntpcal_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 */
285extern int32_t
286ntpcal_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 */
292extern int32_t
293ntpcal_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 */
299extern int32_t
300ntpcal_daysec_to_tm(struct tm * /* utm */, int32_t /* secs */);
301
302extern int32_t
303ntpcal_tm_to_daysec(const struct tm * /* utm */);
304
305/*
306 * convert a year number to rata die of year start
307 */
308extern int32_t
309ntpcal_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 */
315extern int32_t
316ntpcal_rd_to_ystart(int32_t /* rd */);
317
318/*
319 * convert a RataDie to the RataDie of start of the calendar month.
320 */
321extern int32_t
322ntpcal_rd_to_mstart(int32_t /* year */);
323
324
325extern int
326ntpcal_daysplit_to_date(struct calendar * /* jt */,
327			const ntpcal_split * /* ds */, int32_t /* dof */);
328
329extern int
330ntpcal_daysplit_to_tm(struct tm * /* utm */, const ntpcal_split * /* ds */,
331		      int32_t /* dof */);
332
333extern int
334ntpcal_time_to_date(struct calendar * /* jd */, const vint64 * /* ts */);
335
336extern int32_t
337ntpcal_periodic_extend(int32_t /* pivot */, int32_t /* value */,
338		       int32_t /* cycle */);
339
340extern int
341ntpcal_ntp64_to_date(struct calendar * /* jd */, const vint64 * /* ntp */);
342
343extern int
344ntpcal_ntp_to_date(struct calendar * /* jd */,	uint32_t /* ntp */,
345		   const time_t * /* pivot */);
346
347extern vint64
348ntpcal_date_to_ntp64(const struct calendar * /* jd */);
349
350extern uint32_t
351ntpcal_date_to_ntp(const struct calendar * /* jd */);
352
353extern time_t
354ntpcal_date_to_time(const struct calendar * /* jd */);
355
356/*
357 * ISO week-calendar conversions
358 */
359extern int32_t
360isocal_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 */
366extern ntpcal_split
367isocal_split_eraweeks(int32_t /* weeks */);
368
369extern int
370isocal_ntp64_to_date(struct isodate * /* id */, const vint64 * /* ntp */);
371
372extern int
373isocal_ntp_to_date(struct isodate * /* id */, uint32_t /* ntp */,
374		   const time_t * /* pivot */);
375
376extern vint64
377isocal_date_to_ntp64(const struct isodate * /* id */);
378
379extern uint32_t
380isocal_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 */
390extern int32_t
391ntpcal_weekday_gt(int32_t  /* rdn */, int32_t /* dow */);
392
393extern int32_t
394ntpcal_weekday_ge(int32_t /* rdn */, int32_t /* dow */);
395
396extern int32_t
397ntpcal_weekday_close(int32_t /* rdn */, int32_t  /* dow */);
398
399extern int32_t
400ntpcal_weekday_le(int32_t /* rdn */, int32_t /* dow */);
401
402extern int32_t
403ntpcal_weekday_lt(int32_t /* rdn */, int32_t /* dow */);
404
405
406/*
407 * handling of base date spec
408 */
409extern int32_t
410basedate_eval_buildstamp(void);
411
412extern int32_t
413basedate_eval_string(const char *str);
414
415extern int32_t
416basedate_set_day(int32_t dayno);
417
418extern uint32_t
419basedate_get_day(void);
420
421extern time_t
422basedate_get_eracenter(void);
423
424extern time_t
425basedate_get_erabase(void);
426
427extern uint32_t
428basedate_get_gpsweek(void);
429
430extern uint32_t
431basedate_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
523static inline int
524is_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 */
535extern int      u32mod7(uint32_t x);
536extern int      i32mod7(int32_t x);
537extern uint32_t i32fmod(int32_t x, uint32_t d);
538
539extern int32_t ntpcal_expand_century(uint32_t y, uint32_t m, uint32_t d, uint32_t wd);
540
541#endif
542