154359Sroberto/*
254359Sroberto * ntp_calendar.h - definitions for the calendar time-of-day routine
354359Sroberto */
454359Sroberto#ifndef NTP_CALENDAR_H
554359Sroberto#define NTP_CALENDAR_H
654359Sroberto
7280849Scy#include <time.h>
8280849Scy
954359Sroberto#include "ntp_types.h"
1054359Sroberto
11280849Scy/* gregorian calendar date */
1254359Srobertostruct calendar {
13280849Scy	uint16_t year;		/* year (A.D.) */
14280849Scy	uint16_t yearday;	/* day of year, 1 = January 1 */
15280849Scy	uint8_t  month;		/* month, 1 = January */
16280849Scy	uint8_t  monthday;	/* day of month */
17280849Scy	uint8_t  hour;		/* hour of day, midnight = 0 */
18280849Scy	uint8_t  minute;	/* minute of hour */
19280849Scy	uint8_t  second;	/* second of minute */
20280849Scy	uint8_t  weekday;	/* 0..7, 0=Sunday */
2154359Sroberto};
22358659Scytypedef struct calendar TCivilDate;
23358659Scytypedef struct calendar const TcCivilDate;
2454359Sroberto
25280849Scy/* ISO week calendar date */
26280849Scystruct isodate {
27280849Scy	uint16_t year;		/* year (A.D.) */
28280849Scy	uint8_t	 week;		/* 1..53, week in year */
29280849Scy	uint8_t	 weekday;	/* 1..7, 1=Monday */
30280849Scy	uint8_t	 hour;		/* hour of day, midnight = 0 */
31280849Scy	uint8_t	 minute;	/* minute of hour */
32280849Scy	uint8_t	 second;	/* second of minute */
33280849Scy};
34358659Scytypedef struct isodate TIsoDate;
35358659Scytypedef struct isodate const TcIsoDate;
36280849Scy
37280849Scy/* general split representation */
38280849Scytypedef struct {
39280849Scy	int32_t hi;
40280849Scy	int32_t lo;
41280849Scy} ntpcal_split;
42280849Scy
43280849Scytypedef time_t (*systime_func_ptr)(time_t *);
44280849Scy
4554359Sroberto/*
46280849Scy * set the function for getting the system time. This is mostly used for
47280849Scy * unit testing to provide a fixed / shifted time stamp. Setting the
48280849Scy * value to NULL restores the original function, that is, 'time()',
49280849Scy * which is also the automatic default.
5054359Sroberto */
51280849Scyextern systime_func_ptr ntpcal_set_timefunc(systime_func_ptr);
52280849Scy
53280849Scy/*
54280849Scy * days-of-week
55280849Scy */
56280849Scy#define CAL_SUNDAY	0
57280849Scy#define CAL_MONDAY	1
58280849Scy#define CAL_TUESDAY	2
59280849Scy#define CAL_WEDNESDAY	3
60280849Scy#define CAL_THURSDAY	4
61280849Scy#define CAL_FRIDAY	5
62280849Scy#define CAL_SATURDAY	6
63280849Scy#define CAL_SUNDAY7	7	/* also sunday */
64280849Scy
65280849Scy/*
66280849Scy * Days in each month.	30 days hath September...
67280849Scy */
6854359Sroberto#define	JAN	31
6954359Sroberto#define	FEB	28
7054359Sroberto#define	FEBLEAP	29
7154359Sroberto#define	MAR	31
7254359Sroberto#define	APR	30
7354359Sroberto#define	MAY	31
7454359Sroberto#define	JUN	30
7554359Sroberto#define	JUL	31
7654359Sroberto#define	AUG	31
7754359Sroberto#define	SEP	30
7854359Sroberto#define	OCT	31
7954359Sroberto#define	NOV	30
8054359Sroberto#define	DEC	31
8154359Sroberto
8254359Sroberto/*
83280849Scy * We deal in a 4 year cycle starting at March 1, 1900.	 We assume
8454359Sroberto * we will only want to deal with dates since then, and not to exceed
8554359Sroberto * the rollover day in 2036.
8654359Sroberto */
8754359Sroberto#define	SECSPERMIN	(60)			/* seconds per minute */
8854359Sroberto#define	MINSPERHR	(60)			/* minutes per hour */
8954359Sroberto#define	HRSPERDAY	(24)			/* hours per day */
90282408Scy#define	DAYSPERWEEK	(7)			/* days per week */
9154359Sroberto#define	DAYSPERYEAR	(365)			/* days per year */
9254359Sroberto
93280849Scy#define	SECSPERHR	(SECSPERMIN * MINSPERHR)
94280849Scy#define	SECSPERDAY	(SECSPERHR * HRSPERDAY)
95282408Scy#define	SECSPERWEEK	(DAYSPERWEEK * SECSPERDAY)
96280849Scy#define	SECSPERYEAR	(365 * SECSPERDAY)	/* regular year */
9754359Sroberto#define	SECSPERLEAPYEAR	(366 * SECSPERDAY)	/* leap year */
98282408Scy#define	SECSPERAVGYEAR	31556952		/* mean year length over 400yrs */
9954359Sroberto
100344884Scy#define GPSWEEKS	1024			/* GPS week cycle */
10154359Sroberto/*
102280849Scy * Gross hacks.	 I have illicit knowlege that there won't be overflows
10354359Sroberto * here, the compiler often can't tell this.
10454359Sroberto */
105280849Scy#define	TIMES60(val)	((((val)<<4) - (val))<<2)	/* *(16 - 1) * 4 */
10654359Sroberto#define	TIMES24(val)	(((val)<<4) + ((val)<<3))	/* *16 + *8 */
107280849Scy#define	TIMES7(val)	(((val)<<3) - (val))		/* *8  - *1 */
10854359Sroberto#define	TIMESDPERC(val)	(((val)<<10) + ((val)<<8) \
10954359Sroberto			+ ((val)<<7) + ((val)<<5) \
11054359Sroberto			+ ((val)<<4) + ((val)<<2) + (val))	/* *big* hack */
11154359Sroberto
112280849Scy
113280849Scyextern	const char * const months[12];
114280849Scyextern	const char * const daynames[7];
115280849Scy
116358659Scyextern	char *	 ntpcal_iso8601std(char*, size_t, struct calendar const*);
117280849Scyextern	void	 caljulian	(uint32_t, struct calendar *);
118280849Scyextern	uint32_t caltontp	(const struct calendar *);
119280849Scy
12054359Sroberto/*
121280849Scy * Convert between 'time_t' and 'vint64'
12254359Sroberto */
123280849Scyextern vint64 time_to_vint64(const time_t *);
124282408Scyextern time_t vint64_to_time(const vint64 *);
12554359Sroberto
12654359Sroberto/*
127280849Scy * Get the build date & time. ATTENTION: The time zone is not specified!
128280849Scy * This depends entirely on the C compilers' capabilities to properly
129280849Scy * expand the '__TIME__' and '__DATE__' macros, as required by the C
130280849Scy * standard.
13154359Sroberto */
132280849Scyextern int
133280849Scyntpcal_get_build_date(struct calendar * /* jd */);
13454359Sroberto
135280849Scy/*
136280849Scy * Convert a timestamp in NTP scale to a time_t value in the UN*X
137280849Scy * scale with proper epoch unfolding around a given pivot or the
138280849Scy * current system time.
139280849Scy */
140280849Scyextern vint64
141280849Scyntpcal_ntp_to_time(uint32_t /* ntp */, const time_t * /* pivot */);
14254359Sroberto
143280849Scy/*
144280849Scy * Convert a timestamp in NTP scale to a 64bit seconds value in the NTP
145280849Scy * scale with proper epoch unfolding around a given pivot or the current
146280849Scy * system time.
147280849Scy * Note: The pivot must be given in UN*X time scale!
148280849Scy */
149280849Scyextern vint64
150280849Scyntpcal_ntp_to_ntp(uint32_t /* ntp */, const time_t * /* pivot */);
15154359Sroberto
15254359Sroberto/*
153280849Scy * Split a time stamp in seconds into elapsed days and elapsed seconds
154280849Scy * since midnight.
155280849Scy */
156280849Scyextern ntpcal_split
157280849Scyntpcal_daysplit(const vint64 *);
158280849Scy
159280849Scy/*
160358659Scy * Split a time stamp in seconds into elapsed weeks and elapsed seconds
161358659Scy * since start of week.
162358659Scy */
163358659Scyextern ntpcal_split
164358659Scyntpcal_weeksplit(const vint64 *);
165358659Scy
166358659Scy/*
167280849Scy * Merge a number of days and a number of seconds into seconds,
168280849Scy * expressed in 64 bits to avoid overflow.
169280849Scy */
170280849Scyextern vint64
171280849Scyntpcal_dayjoin(int32_t /* days */, int32_t /* seconds */);
172280849Scy
173358659Scy/*
174358659Scy * Merge a number of weeks and a number of seconds into seconds,
175358659Scy * expressed in 64 bits to avoid overflow.
176358659Scy */
177358659Scyextern vint64
178358659Scyntpcal_weekjoin(int32_t /* weeks */, int32_t /* seconds */);
179358659Scy
180289764Sglebius/* Get the number of leap years since epoch for the number of elapsed
181289764Sglebius * full years
182289764Sglebius */
183289764Sglebiusextern int32_t
184289764Sglebiusntpcal_leapyears_in_years(int32_t /* years */);
185289764Sglebius
186280849Scy/*
187280849Scy * Convert elapsed years in Era into elapsed days in Era.
188280849Scy */
189280849Scyextern int32_t
190280849Scyntpcal_days_in_years(int32_t /* years */);
191280849Scy
192280849Scy/*
193280849Scy * Convert a number of elapsed month in a year into elapsed days
194280849Scy * in year.
195280849Scy *
196280849Scy * The month will be normalized, and 'res.hi' will contain the
197280849Scy * excessive years that must be considered when converting the years,
198280849Scy * while 'res.lo' will contain the days since start of the
199280849Scy * year. (Expect the resulting days to be negative, with a positive
200280849Scy * excess! But then, we need no leap year flag, either...)
201280849Scy */
202280849Scyextern ntpcal_split
203280849Scyntpcal_days_in_months(int32_t /* months */);
204280849Scy
205280849Scy/*
206280849Scy * Convert ELAPSED years/months/days of gregorian calendar to elapsed
207280849Scy * days in Gregorian epoch. No range checks done here!
208280849Scy */
209280849Scyextern int32_t
210280849Scyntpcal_edate_to_eradays(int32_t /* years */, int32_t /* months */, int32_t /* mdays */);
211280849Scy
212280849Scy/*
213280849Scy * Convert a time spec to seconds. No range checks done here!
214280849Scy */
215280849Scyextern int32_t
216280849Scyntpcal_etime_to_seconds(int32_t /* hours */, int32_t /* minutes */, int32_t /* seconds */);
217280849Scy
218280849Scy/*
219280849Scy * Convert ELAPSED years/months/days of gregorian calendar to elapsed
220280849Scy * days in year.
221280849Scy *
222280849Scy * Note: This will give the true difference to the start of the given year,
223280849Scy * even if months & days are off-scale.
224280849Scy */
225280849Scyextern int32_t
226280849Scyntpcal_edate_to_yeardays(int32_t /* years */, int32_t /* months */, int32_t /* mdays */);
227280849Scy
228280849Scy/*
229280849Scy * Convert the date part of a 'struct tm' (that is, year, month,
230280849Scy * day-of-month) into the RataDie of that day.
231280849Scy */
232280849Scyextern int32_t
233280849Scyntpcal_tm_to_rd(const struct tm * /* utm */);
234280849Scy
235280849Scy/*
236280849Scy * Convert the date part of a 'struct calendar' (that is, year, month,
237280849Scy * day-of-month) into the RataDie of that day.
238280849Scy */
239280849Scyextern int32_t
240280849Scyntpcal_date_to_rd(const struct calendar * /* jt */);
241280849Scy
242280849Scy/*
243280849Scy * Given the number of elapsed days in the calendar era, split this
244280849Scy * number into the number of elapsed years in 'res.quot' and the
245280849Scy * number of elapsed days of that year in 'res.rem'.
246280849Scy *
247280849Scy * if 'isleapyear' is not NULL, it will receive an integer that is 0
248280849Scy * for regular years and a non-zero value for leap years.
249289764Sglebius *
250289764Sglebius * The input is limited to [-2^30, 2^30-1]. If the days exceed this
251289764Sglebius * range, errno is set to EDOM and the result is saturated.
252280849Scy */
253280849Scyextern ntpcal_split
254280849Scyntpcal_split_eradays(int32_t /* days */, int/*BOOL*/ * /* isleapyear */);
255280849Scy
256280849Scy/*
257280849Scy * Given a number of elapsed days in a year and a leap year indicator,
258280849Scy * split the number of elapsed days into the number of elapsed months
259280849Scy * in 'res.quot' and the number of elapsed days of that month in
260280849Scy * 'res.rem'.
261280849Scy */
262280849Scyextern ntpcal_split
263280849Scyntpcal_split_yeardays(int32_t /* eyd */, int/*BOOL*/ /* isleapyear */);
264280849Scy
265280849Scy/*
266280849Scy * Convert a RataDie number into the date part of a 'struct
267280849Scy * calendar'. Return 0 if the year is regular year, !0 if the year is
268280849Scy * a leap year.
269280849Scy */
270280849Scyextern int/*BOOL*/
271280849Scyntpcal_rd_to_date(struct calendar * /* jt */, int32_t /* rd */);
272280849Scy
273280849Scy/*
274280849Scy * Convert a RataDie number into the date part of a 'struct
275280849Scy * tm'. Return 0 if the year is regular year, !0 if the year is a leap
276280849Scy * year.
277280849Scy */
278280849Scyextern int/*BOOL*/
279280849Scyntpcal_rd_to_tm(struct tm * /* utm */, int32_t /* rd */);
280280849Scy
281280849Scy/*
282280849Scy * Take a value of seconds since midnight and split it into hhmmss in
283280849Scy * a 'struct calendar'. Return excessive days.
284280849Scy */
285280849Scyextern int32_t
286280849Scyntpcal_daysec_to_date(struct calendar * /* jt */, int32_t /* secs */);
287280849Scy
288280849Scy/*
289280849Scy * Take the time part of a 'struct calendar' and return the seconds
290280849Scy * since midnight.
291280849Scy */
292280849Scyextern int32_t
293280849Scyntpcal_date_to_daysec(const struct calendar *);
294280849Scy
295280849Scy/*
296280849Scy * Take a value of seconds since midnight and split it into hhmmss in
297280849Scy * a 'struct tm'. Return excessive days.
298280849Scy */
299280849Scyextern int32_t
300280849Scyntpcal_daysec_to_tm(struct tm * /* utm */, int32_t /* secs */);
301280849Scy
302280849Scyextern int32_t
303280849Scyntpcal_tm_to_daysec(const struct tm * /* utm */);
304280849Scy
305280849Scy/*
306280849Scy * convert a year number to rata die of year start
307280849Scy */
308280849Scyextern int32_t
309280849Scyntpcal_year_to_ystart(int32_t /* year */);
310280849Scy
311280849Scy/*
312280849Scy * For a given RataDie, get the RataDie of the associated year start,
313280849Scy * that is, the RataDie of the last January,1st on or before that day.
314280849Scy */
315280849Scyextern int32_t
316280849Scyntpcal_rd_to_ystart(int32_t /* rd */);
317280849Scy
318280849Scy/*
319280849Scy * convert a RataDie to the RataDie of start of the calendar month.
320280849Scy */
321280849Scyextern int32_t
322280849Scyntpcal_rd_to_mstart(int32_t /* year */);
323280849Scy
324280849Scy
325280849Scyextern int
326280849Scyntpcal_daysplit_to_date(struct calendar * /* jt */,
327280849Scy			const ntpcal_split * /* ds */, int32_t /* dof */);
328280849Scy
329280849Scyextern int
330280849Scyntpcal_daysplit_to_tm(struct tm * /* utm */, const ntpcal_split * /* ds */,
331280849Scy		      int32_t /* dof */);
332280849Scy
333280849Scyextern int
334280849Scyntpcal_time_to_date(struct calendar * /* jd */, const vint64 * /* ts */);
335280849Scy
336280849Scyextern int32_t
337280849Scyntpcal_periodic_extend(int32_t /* pivot */, int32_t /* value */,
338280849Scy		       int32_t /* cycle */);
339280849Scy
340280849Scyextern int
341280849Scyntpcal_ntp64_to_date(struct calendar * /* jd */, const vint64 * /* ntp */);
342280849Scy
343280849Scyextern int
344280849Scyntpcal_ntp_to_date(struct calendar * /* jd */,	uint32_t /* ntp */,
345280849Scy		   const time_t * /* pivot */);
346280849Scy
347280849Scyextern vint64
348280849Scyntpcal_date_to_ntp64(const struct calendar * /* jd */);
349280849Scy
350280849Scyextern uint32_t
351280849Scyntpcal_date_to_ntp(const struct calendar * /* jd */);
352280849Scy
353280849Scyextern time_t
354280849Scyntpcal_date_to_time(const struct calendar * /* jd */);
355280849Scy
356280849Scy/*
357280849Scy * ISO week-calendar conversions
358280849Scy */
359280849Scyextern int32_t
360280849Scyisocal_weeks_in_years(int32_t  /* years */);
361280849Scy
362289764Sglebius/*
363289764Sglebius * The input is limited to [-2^30, 2^30-1]. If the weeks exceed this
364289764Sglebius * range, errno is set to EDOM and the result is saturated.
365289764Sglebius */
366280849Scyextern ntpcal_split
367280849Scyisocal_split_eraweeks(int32_t /* weeks */);
368280849Scy
369280849Scyextern int
370280849Scyisocal_ntp64_to_date(struct isodate * /* id */, const vint64 * /* ntp */);
371280849Scy
372280849Scyextern int
373280849Scyisocal_ntp_to_date(struct isodate * /* id */, uint32_t /* ntp */,
374280849Scy		   const time_t * /* pivot */);
375280849Scy
376280849Scyextern vint64
377280849Scyisocal_date_to_ntp64(const struct isodate * /* id */);
378280849Scy
379280849Scyextern uint32_t
380280849Scyisocal_date_to_ntp(const struct isodate * /* id */);
381280849Scy
382280849Scy
383280849Scy/*
384280849Scy * day-of-week calculations
385280849Scy *
386280849Scy * Given a RataDie and a day-of-week, calculate a RDN that is reater-than,
387280849Scy * greater-or equal, closest, less-or-equal or less-than the given RDN
388280849Scy * and denotes the given day-of-week
389280849Scy */
390280849Scyextern int32_t
391280849Scyntpcal_weekday_gt(int32_t  /* rdn */, int32_t /* dow */);
392280849Scy
393280849Scyextern int32_t
394280849Scyntpcal_weekday_ge(int32_t /* rdn */, int32_t /* dow */);
395280849Scy
396280849Scyextern int32_t
397280849Scyntpcal_weekday_close(int32_t /* rdn */, int32_t  /* dow */);
398280849Scy
399280849Scyextern int32_t
400280849Scyntpcal_weekday_le(int32_t /* rdn */, int32_t /* dow */);
401280849Scy
402280849Scyextern int32_t
403280849Scyntpcal_weekday_lt(int32_t /* rdn */, int32_t /* dow */);
404280849Scy
405330106Sdelphij
406280849Scy/*
407330106Sdelphij * handling of base date spec
408330106Sdelphij */
409330106Sdelphijextern int32_t
410330106Sdelphijbasedate_eval_buildstamp(void);
411330106Sdelphij
412330106Sdelphijextern int32_t
413330106Sdelphijbasedate_eval_string(const char *str);
414330106Sdelphij
415330106Sdelphijextern int32_t
416330106Sdelphijbasedate_set_day(int32_t dayno);
417330106Sdelphij
418330106Sdelphijextern uint32_t
419330106Sdelphijbasedate_get_day(void);
420330106Sdelphij
421330106Sdelphijextern time_t
422330106Sdelphijbasedate_get_eracenter(void);
423330106Sdelphij
424330106Sdelphijextern time_t
425330106Sdelphijbasedate_get_erabase(void);
426330106Sdelphij
427344884Scyextern uint32_t
428344884Scybasedate_get_gpsweek(void);
429330106Sdelphij
430344884Scyextern uint32_t
431344884Scybasedate_expand_gpsweek(unsigned short weekno);
432344884Scy
433330106Sdelphij/*
43454359Sroberto * Additional support stuff for Ed Rheingold's calendrical calculations
43554359Sroberto */
43654359Sroberto
43754359Sroberto/*
438344884Scy * Start day of NTP time as days past 0000-12-31 in the proleptic
439344884Scy * Gregorian calendar. (So 0001-01-01 is day number 1; this is the Rata
440344884Scy * Die counting scheme used by Ed Rheingold in his book "Calendrical
441344884Scy * Calculations".)
44254359Sroberto */
443280849Scy#define	DAY_NTP_STARTS 693596
444280849Scy
44554359Sroberto/*
446280849Scy * Start day of the UNIX epoch. This is the Rata Die of 1970-01-01.
44754359Sroberto */
448280849Scy#define DAY_UNIX_STARTS 719163
44954359Sroberto
45054359Sroberto/*
451344884Scy * Start day of the GPS epoch. This is the Rata Die of 1980-01-06
452344884Scy */
453358659Scy#define DAY_GPS_STARTS 722820
454344884Scy
455344884Scy/*
456280849Scy * Difference between UN*X and NTP epoch (25567).
45754359Sroberto */
458280849Scy#define NTP_TO_UNIX_DAYS (DAY_UNIX_STARTS - DAY_NTP_STARTS)
45954359Sroberto
46054359Sroberto/*
461344884Scy * Difference between GPS and NTP epoch (29224)
462344884Scy */
463344884Scy#define NTP_TO_GPS_DAYS (DAY_GPS_STARTS - DAY_NTP_STARTS)
464344884Scy
465344884Scy/*
466280849Scy * Days in a normal 4 year leap year calendar cycle (1461).
46754359Sroberto */
468344884Scy#define	GREGORIAN_NORMAL_LEAP_CYCLE_DAYS	(4 * 365 + 1)
46954359Sroberto
470280849Scy/*
471280849Scy * Days in a normal 100 year leap year calendar (36524).  We lose a
472280849Scy * leap day in years evenly divisible by 100 but not by 400.
473280849Scy */
474280849Scy#define	GREGORIAN_NORMAL_CENTURY_DAYS	\
475280849Scy			(25 * GREGORIAN_NORMAL_LEAP_CYCLE_DAYS - 1)
47654359Sroberto
477280849Scy/*
478280849Scy * The Gregorian calendar is based on a 400 year cycle. This is the
479280849Scy * number of days in each cycle (146097).  We gain a leap day in years
480280849Scy * divisible by 400 relative to the "normal" century.
481280849Scy */
482280849Scy#define	GREGORIAN_CYCLE_DAYS (4 * GREGORIAN_NORMAL_CENTURY_DAYS + 1)
483280849Scy
484280849Scy/*
485280849Scy * Number of weeks in 400 years (20871).
486280849Scy */
487280849Scy#define	GREGORIAN_CYCLE_WEEKS (GREGORIAN_CYCLE_DAYS / 7)
488280849Scy
489358659Scy/*
490358659Scy * Is a Greogorian calendar year a leap year? The obvious solution is to
491358659Scy * test the expression
492358659Scy *
493358659Scy * (y % 4 == 0) && ((y % 100 != 0) || (y % 400 == 0))
494358659Scy *
495358659Scy * This needs (in theory) 2 true divisions -- most compilers check the
496358659Scy * (mod 4) condition by doing a bit test. Some compilers have been
497358659Scy * even observed to partially fuse the (mod 100) and (mod 400) test,
498358659Scy * but there is an alternative formula that gives the compiler even
499358659Scy * better chances:
500358659Scy *
501358659Scy * (y % 4 == 0) && ((y % 16 == 0) || (y % 25 != 0))
502358659Scy *
503358659Scy * The order of checks is chosen so that the shorcut evaluation can fix
504358659Scy * the result as soon as possible. And the compiler has to do only one
505358659Scy * true division here -- the (mod 4) and (mod 16) can be done with
506358659Scy * direct bit tests. *If* the compiler chooses to do so.
507358659Scy *
508358659Scy * The deduction is as follows: rewrite the standard formula as
509358659Scy *  (y % 4 == 0) && ((y % 4*25 != 0) || (y % 16*25 == 0))
510358659Scy *
511358659Scy * then split the congruences:
512358659Scy *  (y % 4 == 0) && ((y % 4 != 0 || y % 25 != 0) || (y % 16 == 0 && y % 25 == 0))
513358659Scy *
514358659Scy * eliminate the 1st inner term, as it is provably false:
515358659Scy *  (y % 4 == 0) && (y % 25 != 0 || (y % 16 == 0 && y % 25 == 0))
516358659Scy *
517358659Scy * Use the distributive laws on the second major group:
518358659Scy *  (y % 4 == 0) && ((y % 25 != 0 || y % 16 == 0) && (y % 25 != 0 || y % 25 == 0))
519358659Scy *
520358659Scy * Eliminate the constant term, reorder, and voila:
521358659Scy */
522280849Scy
523358659Scystatic inline int
524358659Scyis_leapyear(int32_t y) {
525358659Scy	return !(y % 4) && (!(y % 16) || (y % 25));
526358659Scy}
527358659Scy/* The (mod 4) test eliminates 3/4 (or 12/16) of all values.
528358659Scy * The (mod 16) test eliminates another 1/16 of all values.
529358659Scy * 3/16 of all values reach the final division.
530358659Scy * Assuming that the true division is the most costly operation, this
531358659Scy * sequence should give most bang for the buck.
532358659Scy */
533358659Scy
534358659Scy/* misc */
535358659Scyextern int      u32mod7(uint32_t x);
536358659Scyextern int      i32mod7(int32_t x);
537358659Scyextern uint32_t i32fmod(int32_t x, uint32_t d);
538358659Scy
539358659Scyextern int32_t ntpcal_expand_century(uint32_t y, uint32_t m, uint32_t d, uint32_t wd);
540358659Scy
54154359Sroberto#endif
542