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