xref: /netbsd-src/external/bsd/ntp/dist/libntp/ntp_calendar.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: ntp_calendar.c,v 1.3 2014/01/15 14:40:30 apb Exp $	*/
2 
3 /*
4  * ntp_calendar.c - calendar and helper functions
5  *
6  * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
7  * The contents of 'html/copyright.html' apply.
8  */
9 #include <config.h>
10 #include <sys/types.h>
11 
12 #include "ntp_types.h"
13 #include "ntp_calendar.h"
14 #include "ntp_stdlib.h"
15 #include "ntp_fp.h"
16 #include "ntp_unixtime.h"
17 
18 /*
19  *---------------------------------------------------------------------
20  * replacing the 'time()' function
21  * --------------------------------------------------------------------
22  */
23 
24 static systime_func_ptr systime_func = &time;
25 static inline time_t now(void);
26 
27 
28 systime_func_ptr
29 ntpcal_set_timefunc(
30 	systime_func_ptr nfunc
31 	)
32 {
33 	systime_func_ptr res;
34 
35 	res = systime_func;
36 	if (NULL == nfunc)
37 		nfunc = &time;
38 	systime_func = nfunc;
39 
40 	return res;
41 }
42 
43 
44 static inline time_t
45 now(void)
46 {
47 	return (*systime_func)(NULL);
48 }
49 
50 /*
51  *---------------------------------------------------------------------
52  * Convert between 'time_t' and 'vint64'
53  *---------------------------------------------------------------------
54  */
55 vint64
56 time_to_vint64(
57 	const time_t * ptt
58 	)
59 {
60 	vint64 res;
61 	time_t tt;
62 
63 	tt = *ptt;
64 
65 #if SIZEOF_TIME_T <= 4
66 
67 	res.D_s.hi = 0;
68 	if (tt < 0) {
69 		res.D_s.lo = (uint32_t)-tt;
70 		M_NEG(res.D_s.hi, res.D_s.lo);
71 	} else {
72 		res.D_s.lo = (uint32_t)tt;
73 	}
74 
75 #elif defined(HAVE_INT64)
76 
77 	res.q_s = tt;
78 
79 #else
80 	/*
81 	 * shifting negative signed quantities is compiler-dependent, so
82 	 * we better avoid it and do it all manually. And shifting more
83 	 * than the width of a quantity is undefined. Also a don't do!
84 	 */
85 	if (tt < 0) {
86 		tt = -tt;
87 		res.D_s.lo = (uint32_t)tt;
88 		res.D_s.hi = (uint32_t)(tt >> 32);
89 		M_NEG(res.D_s.hi, res.D_s.lo);
90 	} else {
91 		res.D_s.lo = (uint32_t)tt;
92 		res.D_s.hi = (uint32_t)(tt >> 32);
93 	}
94 
95 #endif
96 
97 	return res;
98 }
99 
100 
101 time_t
102 vint64_to_time(
103 	const vint64 *tv
104 	)
105 {
106 	time_t res;
107 
108 #if SIZEOF_TIME_T <= 4
109 
110 	res = (time_t)tv->D_s.lo;
111 
112 #elif defined(HAVE_INT64)
113 
114 	res = (time_t)tv->q_s;
115 
116 #else
117 
118 	res = ((time_t)tv->d_s.hi << 32) | tv->D_s.lo;
119 
120 #endif
121 
122 	return res;
123 }
124 
125 /*
126  *---------------------------------------------------------------------
127  * Get the build date & time
128  *---------------------------------------------------------------------
129  */
130 int
131 ntpcal_get_build_date(
132 	struct calendar * jd
133 	)
134 {
135 	/* The C standard tells us the format of '__DATE__':
136 	 *
137 	 * __DATE__ The date of translation of the preprocessing
138 	 * translation unit: a character string literal of the form "Mmm
139 	 * dd yyyy", where the names of the months are the same as those
140 	 * generated by the asctime function, and the first character of
141 	 * dd is a space character if the value is less than 10. If the
142 	 * date of translation is not available, an
143 	 * implementation-defined valid date shall be supplied.
144 	 *
145 	 * __TIME__ The time of translation of the preprocessing
146 	 * translation unit: a character string literal of the form
147 	 * "hh:mm:ss" as in the time generated by the asctime
148 	 * function. If the time of translation is not available, an
149 	 * implementation-defined valid time shall be supplied.
150 	 *
151 	 * Note that MSVC declares DATE and TIME to be in the local time
152 	 * zone, while neither the C standard nor the GCC docs make any
153 	 * statement about this. As a result, we may be +/-12hrs off
154 	 * UTC.  But for practical purposes, this should not be a
155 	 * problem.
156 	 *
157 	 */
158 #ifdef MKREPRO_DATE
159 	static const char build[] = MKREPRO_TIME "/" MKREPRO_DATE;
160 #else
161 	static const char build[] = __TIME__ "/" __DATE__;
162 #endif
163 	static const char mlist[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
164 	char		  monstr[4];
165 	const char *	  cp;
166 	unsigned short	  hour, minute, second, day, year;
167 	/* Note: The above quantities are used for sscanf 'hu' format,
168 	 * so using 'uint16_t' is contra-indicated!
169 	 */
170 
171 	ZERO(*jd);
172 	jd->year     = 1970;
173 	jd->month    = 1;
174 	jd->monthday = 1;
175 
176 	if (6 == sscanf(build, "%hu:%hu:%hu/%3s %hu %hu",
177 			&hour, &minute, &second, monstr, &day, &year)) {
178 		cp = strstr(mlist, monstr);
179 		if (NULL != cp) {
180 			jd->year     = year;
181 			jd->month    = (uint8_t)((cp - mlist) / 3 + 1);
182 			jd->monthday = (uint8_t)day;
183 			jd->hour     = (uint8_t)hour;
184 			jd->minute   = (uint8_t)minute;
185 			jd->second   = (uint8_t)second;
186 
187 			return TRUE;
188 		}
189 	}
190 
191 	return FALSE;
192 }
193 
194 
195 /*
196  *---------------------------------------------------------------------
197  * basic calendar stuff
198  * --------------------------------------------------------------------
199  */
200 
201 /* month table for a year starting with March,1st */
202 static const uint16_t shift_month_table[13] = {
203 	0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337, 366
204 };
205 
206 /* month tables for years starting with January,1st; regular & leap */
207 static const uint16_t real_month_table[2][13] = {
208 	/* -*- table for regular years -*- */
209 	{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
210 	/* -*- table for leap years -*- */
211 	{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
212 };
213 
214 /*
215  * Some notes on the terminology:
216  *
217  * We use the proleptic Gregorian calendar, which is the Gregorian
218  * calendar extended in both directions ad infinitum. This totally
219  * disregards the fact that this calendar was invented in 1582, and
220  * was adopted at various dates over the world; sometimes even after
221  * the start of the NTP epoch.
222  *
223  * Normally date parts are given as current cycles, while time parts
224  * are given as elapsed cycles:
225  *
226  * 1970-01-01/03:04:05 means 'IN the 1970st. year, IN the first month,
227  * ON the first day, with 3hrs, 4minutes and 5 seconds elapsed.
228  *
229  * The basic calculations for this calendar implementation deal with
230  * ELAPSED date units, which is the number of full years, full months
231  * and full days before a date: 1970-01-01 would be (1969, 0, 0) in
232  * that notation.
233  *
234  * To ease the numeric computations, month and day values outside the
235  * normal range are acceptable: 2001-03-00 will be treated as the day
236  * before 2001-03-01, 2000-13-32 will give the same result as
237  * 2001-02-01 and so on.
238  *
239  * 'rd' or 'RD' is used as an abbreviation for the latin 'rata die'
240  * (day number).  This is the number of days elapsed since 0000-12-31
241  * in the proleptic Gregorian calendar. The begin of the Christian Era
242  * (0001-01-01) is RD(1).
243  *
244  *
245  * Some notes on the implementation:
246  *
247  * Calendar algorithms thrive on the division operation, which is one of
248  * the slowest numerical operations in any CPU. What saves us here from
249  * abysmal performance is the fact that all divisions are divisions by
250  * constant numbers, and most compilers can do this by a multiplication
251  * operation.  But this might not work when using the div/ldiv/lldiv
252  * function family, because many compilers are not able to do inline
253  * expansion of the code with following optimisation for the
254  * constant-divider case.
255  *
256  * Also div/ldiv/lldiv are defined in terms of int/long/longlong, which
257  * are inherently target dependent. Nothing that could not be cured with
258  * autoconf, but still a mess...
259  *
260  * Furthermore, we need floor division while C demands truncation to
261  * zero, so additional steps are required to make sure the algorithms
262  * work.
263  *
264  * For all this, all divisions by constant are coded manually, even when
265  * there is a joined div/mod operation: The optimiser should sort that
266  * out, if possible.
267  *
268  * Finally, the functions do not check for overflow conditions. This
269  * is a sacrifice made for execution speed; since a 32-bit day counter
270  * covers +/- 5,879,610 years, this should not pose a problem here.
271  */
272 
273 
274 /*
275  * ==================================================================
276  *
277  * General algorithmic stuff
278  *
279  * ==================================================================
280  */
281 
282 /*
283  *---------------------------------------------------------------------
284  * Do a periodic extension of 'value' around 'pivot' with a period of
285  * 'cycle'.
286  *
287  * The result 'res' is a number that holds to the following properties:
288  *
289  *   1)	 res MOD cycle == value MOD cycle
290  *   2)	 pivot <= res < pivot + cycle
291  *	 (replace </<= with >/>= for negative cycles)
292  *
293  * where 'MOD' denotes the modulo operator for FLOOR DIVISION, which
294  * is not the same as the '%' operator in C: C requires division to be
295  * a truncated division, where remainder and dividend have the same
296  * sign if the remainder is not zero, whereas floor division requires
297  * divider and modulus to have the same sign for a non-zero modulus.
298  *
299  * This function has some useful applications:
300  *
301  * + let Y be a calendar year and V a truncated 2-digit year: then
302  *	periodic_extend(Y-50, V, 100)
303  *   is the closest expansion of the truncated year with respect to
304  *   the full year, that is a 4-digit year with a difference of less
305  *   than 50 years to the year Y. ("century unfolding")
306  *
307  * + let T be a UN*X time stamp and V be seconds-of-day: then
308  *	perodic_extend(T-43200, V, 86400)
309  *   is a time stamp that has the same seconds-of-day as the input
310  *   value, with an absolute difference to T of <= 12hrs.  ("day
311  *   unfolding")
312  *
313  * + Wherever you have a truncated periodic value and a non-truncated
314  *   base value and you want to match them somehow...
315  *
316  * Basically, the function delivers 'pivot + (value - pivot) % cycle',
317  * but the implementation takes some pains to avoid internal signed
318  * integer overflows in the '(value - pivot) % cycle' part and adheres
319  * to the floor division convention.
320  *
321  * If 64bit scalars where available on all intended platforms, writing a
322  * version that uses 64 bit ops would be easy; writing a general
323  * division routine for 64bit ops on a platform that can only do
324  * 32/16bit divisions and is still performant is a bit more
325  * difficult. Since most usecases can be coded in a way that does only
326  * require the 32-bit version a 64bit version is NOT provided here.
327  * ---------------------------------------------------------------------
328  */
329 int32_t
330 ntpcal_periodic_extend(
331 	int32_t pivot,
332 	int32_t value,
333 	int32_t cycle
334 	)
335 {
336 	uint32_t diff;
337 	char	 cpl = 0; /* modulo complement flag */
338 	char	 neg = 0; /* sign change flag	    */
339 
340 	/* make the cycle positive and adjust the flags */
341 	if (cycle < 0) {
342 		cycle = - cycle;
343 		neg ^= 1;
344 		cpl ^= 1;
345 	}
346 	/* guard against div by zero or one */
347 	if (cycle > 1) {
348 		/*
349 		 * Get absolute difference as unsigned quantity and
350 		 * the complement flag. This is done by always
351 		 * subtracting the smaller value from the bigger
352 		 * one. This implementation works only on a two's
353 		 * complement machine!
354 		 */
355 		if (value >= pivot) {
356 			diff = (uint32_t)value - (uint32_t)pivot;
357 		} else {
358 			diff = (uint32_t)pivot - (uint32_t)value;
359 			cpl ^= 1;
360 		}
361 		diff %= (uint32_t)cycle;
362 		if (diff) {
363 			if (cpl)
364 				diff = cycle - diff;
365 			if (neg)
366 				diff = ~diff + 1;
367 			pivot += diff;
368 		}
369 	}
370 	return pivot;
371 }
372 
373 /*
374  *-------------------------------------------------------------------
375  * Convert a timestamp in NTP scale to a 64bit seconds value in the UN*X
376  * scale with proper epoch unfolding around a given pivot or the current
377  * system time. This function happily accepts negative pivot values as
378  * timestamps befor 1970-01-01, so be aware of possible trouble on
379  * platforms with 32bit 'time_t'!
380  *
381  * This is also a periodic extension, but since the cycle is 2^32 and
382  * the shift is 2^31, we can do some *very* fast math without explicit
383  * divisions.
384  *-------------------------------------------------------------------
385  */
386 vint64
387 ntpcal_ntp_to_time(
388 	uint32_t	ntp,
389 	const time_t *	pivot
390 	)
391 {
392 	vint64 res;
393 
394 #ifdef HAVE_INT64
395 
396 	res.q_s = (pivot != NULL)
397 		      ? *pivot
398 		      : now();
399 	res.Q_s -= 0x80000000;		/* unshift of half range */
400 	ntp	-= (uint32_t)JAN_1970;	/* warp into UN*X domain */
401 	ntp	-= res.D_s.lo;		/* cycle difference	 */
402 	res.Q_s += (uint64_t)ntp;	/* get expanded time	 */
403 
404 #else /* no 64bit scalars */
405 
406 	time_t tmp;
407 
408 	tmp = (pivot != NULL)
409 		  ? *pivot
410 		  : now();
411 	res = time_to_vint64(&tmp);
412 	M_SUB(res.D_s.hi, res.D_s.lo, 0, 0x80000000);
413 	ntp -= (uint32_t)JAN_1970;	/* warp into UN*X domain */
414 	ntp -= res.D_s.lo;		/* cycle difference	 */
415 	M_ADD(res.D_s.hi, res.D_s.lo, 0, ntp);
416 
417 #endif /* no 64bit scalars */
418 
419 	return res;
420 }
421 
422 /*
423  *-------------------------------------------------------------------
424  * Convert a timestamp in NTP scale to a 64bit seconds value in the NTP
425  * scale with proper epoch unfolding around a given pivot or the current
426  * system time.
427  *
428  * Note: The pivot must be given in the UN*X time domain!
429  *
430  * This is also a periodic extension, but since the cycle is 2^32 and
431  * the shift is 2^31, we can do some *very* fast math without explicit
432  * divisions.
433  *-------------------------------------------------------------------
434  */
435 vint64
436 ntpcal_ntp_to_ntp(
437 	uint32_t      ntp,
438 	const time_t *pivot
439 	)
440 {
441 	vint64 res;
442 
443 #ifdef HAVE_INT64
444 
445 	res.q_s = (pivot)
446 		      ? *pivot
447 		      : now();
448 	res.Q_s -= 0x80000000;		/* unshift of half range */
449 	res.Q_s += (uint32_t)JAN_1970;	/* warp into NTP domain	 */
450 	ntp	-= res.D_s.lo;		/* cycle difference	 */
451 	res.Q_s += (uint64_t)ntp;	/* get expanded time	 */
452 
453 #else /* no 64bit scalars */
454 
455 	time_t tmp;
456 
457 	tmp = (pivot)
458 		  ? *pivot
459 		  : now();
460 	res = time_to_vint64(&tmp);
461 	M_SUB(res.D_s.hi, res.D_s.lo, 0, 0x80000000u);
462 	M_ADD(res.D_s.hi, res.D_s.lo, 0, (uint32_t)JAN_1970);/*into NTP */
463 	ntp -= res.D_s.lo;		/* cycle difference	 */
464 	M_ADD(res.D_s.hi, res.D_s.lo, 0, ntp);
465 
466 #endif /* no 64bit scalars */
467 
468 	return res;
469 }
470 
471 
472 /*
473  * ==================================================================
474  *
475  * Splitting values to composite entities
476  *
477  * ==================================================================
478  */
479 
480 /*
481  *-------------------------------------------------------------------
482  * Split a 64bit seconds value into elapsed days in 'res.hi' and
483  * elapsed seconds since midnight in 'res.lo' using explicit floor
484  * division. This function happily accepts negative time values as
485  * timestamps before the respective epoch start.
486  * -------------------------------------------------------------------
487  */
488 ntpcal_split
489 ntpcal_daysplit(
490 	const vint64 *ts
491 	)
492 {
493 	ntpcal_split res;
494 
495 #ifdef HAVE_INT64
496 
497 	/* manual floor division by SECSPERDAY */
498 	res.hi = (int32_t)(ts->q_s / SECSPERDAY);
499 	res.lo = (int32_t)(ts->q_s % SECSPERDAY);
500 	if (res.lo < 0) {
501 		res.hi -= 1;
502 		res.lo += SECSPERDAY;
503 	}
504 
505 #else
506 
507 	/*
508 	 * since we do not have 64bit ops, we have to this by hand.
509 	 * Luckily SECSPERDAY is 86400 is 675*128, so we do the division
510 	 * using chained 32/16 bit divisions and shifts.
511 	 */
512 	vint64	 op;
513 	uint32_t q, r, a;
514 	int	 isneg;
515 
516 	memcpy(&op, ts, sizeof(op));
517 	/* fix sign */
518 	isneg = M_ISNEG(op.D_s.hi);
519 	if (isneg)
520 		M_NEG(op.D_s.hi, op.D_s.lo);
521 
522 	/* save remainder of DIV 128, shift for divide */
523 	r  = op.D_s.lo & 127; /* save remainder bits */
524 	op.D_s.lo = (op.D_s.lo >> 7) | (op.D_s.hi << 25);
525 	op.D_s.hi = (op.D_s.hi >> 7);
526 
527 	/* now do a mnual division, trying to remove as many ops as
528 	 * possible -- division is always slow! An since we do not have
529 	 * the advantage of a specific 64/32 bit or even a specific 32/16
530 	 * bit division op, but must use the general 32/32bit division
531 	 * even if we *know* the divider fits into unsigned 16 bits, the
532 	 * exra code pathes should pay off.
533 	 */
534 	a = op.D_s.hi;
535 	if (a > 675u)
536 		a = a % 675u;
537 	if (a) {
538 		a = (a << 16) | op.W_s.lh;
539 		q = a / 675u;
540 		a = a % 675u;
541 
542 		a = (a << 16) | op.W_s.ll;
543 		q = (q << 16) | (a / 675u);
544 	} else {
545 		a = op.D_s.lo;
546 		q = a / 675u;
547 	}
548 	a = a % 675u;
549 
550 	/* assemble remainder */
551 	r |= a << 7;
552 
553 	/* fix sign of result */
554 	if (isneg) {
555 		if (r) {
556 			r = SECSPERDAY - r;
557 			q = ~q;
558 		} else
559 			q = ~q + 1;
560 	}
561 
562 	res.hi = q;
563 	res.lo = r;
564 
565 #endif
566 	return res;
567 }
568 
569 /*
570  *-------------------------------------------------------------------
571  * Split a 32bit seconds value into h/m/s and excessive days.  This
572  * function happily accepts negative time values as timestamps before
573  * midnight.
574  * -------------------------------------------------------------------
575  */
576 static int32_t
577 priv_timesplit(
578 	int32_t split[3],
579 	int32_t ts
580 	)
581 {
582 	int32_t days = 0;
583 
584 	/* make sure we have a positive offset into a day */
585 	if (ts < 0 || ts >= SECSPERDAY) {
586 		days = ts / SECSPERDAY;
587 		ts   = ts % SECSPERDAY;
588 		if (ts < 0) {
589 			days -= 1;
590 			ts   += SECSPERDAY;
591 		}
592 	}
593 
594 	/* get secs, mins, hours */
595 	split[2] = (uint8_t)(ts % SECSPERMIN);
596 	ts /= SECSPERMIN;
597 	split[1] = (uint8_t)(ts % MINSPERHR);
598 	split[0] = (uint8_t)(ts / MINSPERHR);
599 
600 	return days;
601 }
602 
603 /*
604  * ---------------------------------------------------------------------
605  * Given the number of elapsed days in the calendar era, split this
606  * number into the number of elapsed years in 'res.hi' and the number
607  * of elapsed days of that year in 'res.lo'.
608  *
609  * if 'isleapyear' is not NULL, it will receive an integer that is 0 for
610  * regular years and a non-zero value for leap years.
611  *---------------------------------------------------------------------
612  */
613 ntpcal_split
614 ntpcal_split_eradays(
615 	int32_t days,
616 	int  *isleapyear
617 	)
618 {
619 	ntpcal_split res;
620 	int32_t	     n400, n100, n004, n001, yday; /* calendar year cycles */
621 
622 	/*
623 	 * Split off calendar cycles, using floor division in the first
624 	 * step. After that first step, simple division does it because
625 	 * all operands are positive; alas, we have to be aware of the
626 	 * possibe cycle overflows for 100 years and 1 year, caused by
627 	 * the additional leap day.
628 	 */
629 	n400 = days / GREGORIAN_CYCLE_DAYS;
630 	yday = days % GREGORIAN_CYCLE_DAYS;
631 	if (yday < 0) {
632 		n400 -= 1;
633 		yday += GREGORIAN_CYCLE_DAYS;
634 	}
635 	n100 = yday / GREGORIAN_NORMAL_CENTURY_DAYS;
636 	yday = yday % GREGORIAN_NORMAL_CENTURY_DAYS;
637 	n004 = yday / GREGORIAN_NORMAL_LEAP_CYCLE_DAYS;
638 	yday = yday % GREGORIAN_NORMAL_LEAP_CYCLE_DAYS;
639 	n001 = yday / DAYSPERYEAR;
640 	yday = yday % DAYSPERYEAR;
641 
642 	/*
643 	 * check for leap cycle overflows and calculate the leap flag
644 	 * if needed
645 	 */
646 	if ((n001 | n100) > 3) {
647 		/* hit last day of leap year */
648 		n001 -= 1;
649 		yday += DAYSPERYEAR;
650 		if (isleapyear)
651 			*isleapyear = 1;
652 	} else if (isleapyear)
653 		*isleapyear = (n001 == 3) && ((n004 != 24) || (n100 == 3));
654 
655 	/* now merge the cycles to elapsed years, using horner scheme */
656 	res.hi = ((4*n400 + n100)*25 + n004)*4 + n001;
657 	res.lo = yday;
658 
659 	return res;
660 }
661 
662 /*
663  *---------------------------------------------------------------------
664  * Given a number of elapsed days in a year and a leap year indicator,
665  * split the number of elapsed days into the number of elapsed months in
666  * 'res.hi' and the number of elapsed days of that month in 'res.lo'.
667  *
668  * This function will fail and return {-1,-1} if the number of elapsed
669  * days is not in the valid range!
670  *---------------------------------------------------------------------
671  */
672 ntpcal_split
673 ntpcal_split_yeardays(
674 	int32_t eyd,
675 	int     isleapyear
676 	)
677 {
678 	ntpcal_split    res;
679 	const uint16_t *lt;	/* month length table	*/
680 
681 	/* check leap year flag and select proper table */
682 	lt = real_month_table[(isleapyear != 0)];
683 	if (0 <= eyd && eyd < lt[12]) {
684 		/* get zero-based month by approximation & correction step */
685 		res.hi = eyd >> 5;	   /* approx month; might be 1 too low */
686 		if (lt[res.hi + 1] <= eyd) /* fixup approximative month value  */
687 			res.hi += 1;
688 		res.lo = eyd - lt[res.hi];
689 	} else {
690 		res.lo = res.hi = -1;
691 	}
692 
693 	return res;
694 }
695 
696 /*
697  *---------------------------------------------------------------------
698  * Convert a RD into the date part of a 'struct calendar'.
699  *---------------------------------------------------------------------
700  */
701 int
702 ntpcal_rd_to_date(
703 	struct calendar *jd,
704 	int32_t		 rd
705 	)
706 {
707 	ntpcal_split split;
708 	int	     leaps;
709 	int	     retv;
710 
711 	leaps = 0;
712 	retv = 0;
713 	/* get day-of-week first */
714 	jd->weekday = rd % 7;
715 	if (jd->weekday >= 7)	/* unsigned! */
716 		jd->weekday += 7;
717 
718 	split = ntpcal_split_eradays(rd - 1, &leaps);
719 	retv  = leaps;
720 	/* get year and day-of-year */
721 	jd->year = (uint16_t)split.hi + 1;
722 	if (jd->year != split.hi + 1) {
723 		jd->year = 0;
724 		retv	 = -1;	/* bletch. overflow trouble. */
725 	}
726 	jd->yearday = (uint16_t)split.lo + 1;
727 
728 	/* convert to month and mday */
729 	split = ntpcal_split_yeardays(split.lo, leaps);
730 	jd->month    = (uint8_t)split.hi + 1;
731 	jd->monthday = (uint8_t)split.lo + 1;
732 
733 	return retv ? retv : leaps;
734 }
735 
736 /*
737  *---------------------------------------------------------------------
738  * Convert a RD into the date part of a 'struct tm'.
739  *---------------------------------------------------------------------
740  */
741 int
742 ntpcal_rd_to_tm(
743 	struct tm  *utm,
744 	int32_t	    rd
745 	)
746 {
747 	ntpcal_split split;
748 	int	     leaps;
749 
750 	leaps = 0;
751 	/* get day-of-week first */
752 	utm->tm_wday = rd % 7;
753 	if (utm->tm_wday < 0)
754 		utm->tm_wday += 7;
755 
756 	/* get year and day-of-year */
757 	split = ntpcal_split_eradays(rd - 1, &leaps);
758 	utm->tm_year = split.hi - 1899;
759 	utm->tm_yday = split.lo;	/* 0-based */
760 
761 	/* convert to month and mday */
762 	split = ntpcal_split_yeardays(split.lo, leaps);
763 	utm->tm_mon  = split.hi;	/* 0-based */
764 	utm->tm_mday = split.lo + 1;	/* 1-based */
765 
766 	return leaps;
767 }
768 
769 /*
770  *---------------------------------------------------------------------
771  * Take a value of seconds since midnight and split it into hhmmss in a
772  * 'struct calendar'.
773  *---------------------------------------------------------------------
774  */
775 int32_t
776 ntpcal_daysec_to_date(
777 	struct calendar *jd,
778 	int32_t		sec
779 	)
780 {
781 	int32_t days;
782 	int   ts[3];
783 
784 	days = priv_timesplit(ts, sec);
785 	jd->hour   = (uint8_t)ts[0];
786 	jd->minute = (uint8_t)ts[1];
787 	jd->second = (uint8_t)ts[2];
788 
789 	return days;
790 }
791 
792 /*
793  *---------------------------------------------------------------------
794  * Take a value of seconds since midnight and split it into hhmmss in a
795  * 'struct tm'.
796  *---------------------------------------------------------------------
797  */
798 int32_t
799 ntpcal_daysec_to_tm(
800 	struct tm *utm,
801 	int32_t	   sec
802 	)
803 {
804 	int32_t days;
805 	int32_t ts[3];
806 
807 	days = priv_timesplit(ts, sec);
808 	utm->tm_hour = ts[0];
809 	utm->tm_min  = ts[1];
810 	utm->tm_sec  = ts[2];
811 
812 	return days;
813 }
814 
815 /*
816  *---------------------------------------------------------------------
817  * take a split representation for day/second-of-day and day offset
818  * and convert it to a 'struct calendar'. The seconds will be normalised
819  * into the range of a day, and the day will be adjusted accordingly.
820  *
821  * returns >0 if the result is in a leap year, 0 if in a regular
822  * year and <0 if the result did not fit into the calendar struct.
823  *---------------------------------------------------------------------
824  */
825 int
826 ntpcal_daysplit_to_date(
827 	struct calendar	   *jd,
828 	const ntpcal_split *ds,
829 	int32_t		    dof
830 	)
831 {
832 	dof += ntpcal_daysec_to_date(jd, ds->lo);
833 	return ntpcal_rd_to_date(jd, ds->hi + dof);
834 }
835 
836 /*
837  *---------------------------------------------------------------------
838  * take a split representation for day/second-of-day and day offset
839  * and convert it to a 'struct tm'. The seconds will be normalised
840  * into the range of a day, and the day will be adjusted accordingly.
841  *
842  * returns 1 if the result is in a leap year and zero if in a regular
843  * year.
844  *---------------------------------------------------------------------
845  */
846 int
847 ntpcal_daysplit_to_tm(
848 	struct tm	   *utm,
849 	const ntpcal_split *ds ,
850 	int32_t		    dof
851 	)
852 {
853 	dof += ntpcal_daysec_to_tm(utm, ds->lo);
854 
855 	return ntpcal_rd_to_tm(utm, ds->hi + dof);
856 }
857 
858 /*
859  *---------------------------------------------------------------------
860  * Take a UN*X time and convert to a calendar structure.
861  *---------------------------------------------------------------------
862  */
863 int
864 ntpcal_time_to_date(
865 	struct calendar	*jd,
866 	const vint64	*ts
867 	)
868 {
869 	ntpcal_split ds;
870 
871 	ds = ntpcal_daysplit(ts);
872 	ds.hi += ntpcal_daysec_to_date(jd, ds.lo);
873 	ds.hi += DAY_UNIX_STARTS;
874 
875 	return ntpcal_rd_to_date(jd, ds.hi);
876 }
877 
878 
879 /*
880  * ==================================================================
881  *
882  * merging composite entities
883  *
884  * ==================================================================
885  */
886 
887 /*
888  *---------------------------------------------------------------------
889  * Merge a number of days and a number of seconds into seconds,
890  * expressed in 64 bits to avoid overflow.
891  *---------------------------------------------------------------------
892  */
893 vint64
894 ntpcal_dayjoin(
895 	int32_t days,
896 	int32_t secs
897 	)
898 {
899 	vint64 res;
900 
901 #ifdef HAVE_INT64
902 
903 	res.q_s	 = days;
904 	res.q_s *= SECSPERDAY;
905 	res.q_s += secs;
906 
907 #else
908 
909 	uint32_t p1, p2;
910 	int	 isneg;
911 
912 	/*
913 	 * res = days *86400 + secs, using manual 16/32 bit
914 	 * multiplications and shifts.
915 	 */
916 	isneg = (days < 0);
917 	if (isneg)
918 		days = -days;
919 
920 	/* assemble days * 675 */
921 	res.D_s.lo = (days & 0xFFFF) * 675u;
922 	res.D_s.hi = 0;
923 	p1 = (days >> 16) * 675u;
924 	p2 = p1 >> 16;
925 	p1 = p1 << 16;
926 	M_ADD(res.D_s.hi, res.D_s.lo, p2, p1);
927 
928 	/* mul by 128, using shift */
929 	res.D_s.hi = (res.D_s.hi << 7) | (res.D_s.lo >> 25);
930 	res.D_s.lo = (res.D_s.lo << 7);
931 
932 	/* fix sign */
933 	if (isneg)
934 		M_NEG(res.D_s.hi, res.D_s.lo);
935 
936 	/* properly add seconds */
937 	p2 = 0;
938 	if (secs < 0) {
939 		p1 = (uint32_t)-secs;
940 		M_NEG(p2, p1);
941 	} else {
942 		p1 = (uint32_t)secs;
943 	}
944 	M_ADD(res.D_s.hi, res.D_s.lo, p2, p1);
945 
946 #endif
947 
948 	return res;
949 }
950 
951 /*
952  *---------------------------------------------------------------------
953  * Convert elapsed years in Era into elapsed days in Era.
954  *
955  * To accomodate for negative values of years, floor division would be
956  * required for all division operations. This can be eased by first
957  * splitting the years into full 400-year cycles and years in the
958  * cycle. Only this operation must be coded as a full floor division; as
959  * the years in the cycle is a non-negative number, all other divisions
960  * can be regular truncated divisions.
961  *---------------------------------------------------------------------
962  */
963 int32_t
964 ntpcal_days_in_years(
965 	int32_t years
966 	)
967 {
968 	int32_t cycle; /* full gregorian cycle */
969 
970 	/* split off full calendar cycles, using floor division */
971 	cycle = years / 400;
972 	years = years % 400;
973 	if (years < 0) {
974 		cycle -= 1;
975 		years += 400;
976 	}
977 
978 	/*
979 	 * Calculate days in cycle. years now is a non-negative number,
980 	 * holding the number of years in the 400-year cycle.
981 	 */
982 	return cycle * GREGORIAN_CYCLE_DAYS
983 	     + years * DAYSPERYEAR	/* days inregular years	*/
984 	     + years / 4		/* 4 year leap rule	*/
985 	     - years / 100;		/* 100 year leap rule	*/
986 	/* the 400-year rule does not apply due to full-cycle split-off */
987 }
988 
989 /*
990  *---------------------------------------------------------------------
991  * Convert a number of elapsed month in a year into elapsed days in year.
992  *
993  * The month will be normalized, and 'res.hi' will contain the
994  * excessive years that must be considered when converting the years,
995  * while 'res.lo' will contain the number of elapsed days since start
996  * of the year.
997  *
998  * This code uses the shifted-month-approach to convert month to days,
999  * because then there is no need to have explicit leap year
1000  * information.	 The slight disadvantage is that for most month values
1001  * the result is a negative value, and the year excess is one; the
1002  * conversion is then simply based on the start of the following year.
1003  *---------------------------------------------------------------------
1004  */
1005 ntpcal_split
1006 ntpcal_days_in_months(
1007 	int32_t m
1008 	)
1009 {
1010 	ntpcal_split res;
1011 
1012 	/* normalize month into range */
1013 	res.hi = 0;
1014 	res.lo = m;
1015 	if (res.lo < 0 || res.lo >= 12) {
1016 		res.hi = res.lo / 12;
1017 		res.lo = res.lo % 12;
1018 		if (res.lo < 0) {
1019 			res.hi -= 1;
1020 			res.lo += 12;
1021 		}
1022 	}
1023 
1024 	/* add 10 month for year starting with march */
1025 	if (res.lo < 2)
1026 		res.lo += 10;
1027 	else {
1028 		res.hi += 1;
1029 		res.lo -= 2;
1030 	}
1031 
1032 	/* get cummulated days in year with unshift */
1033 	res.lo = shift_month_table[res.lo] - 306;
1034 
1035 	return res;
1036 }
1037 
1038 /*
1039  *---------------------------------------------------------------------
1040  * Convert ELAPSED years/months/days of gregorian calendar to elapsed
1041  * days in Gregorian epoch.
1042  *
1043  * If you want to convert years and days-of-year, just give a month of
1044  * zero.
1045  *---------------------------------------------------------------------
1046  */
1047 int32_t
1048 ntpcal_edate_to_eradays(
1049 	int32_t years,
1050 	int32_t mons,
1051 	int32_t mdays
1052 	)
1053 {
1054 	ntpcal_split tmp;
1055 	int32_t	     res;
1056 
1057 	if (mons) {
1058 		tmp = ntpcal_days_in_months(mons);
1059 		res = ntpcal_days_in_years(years + tmp.hi) + tmp.lo;
1060 	} else
1061 		res = ntpcal_days_in_years(years);
1062 	res += mdays;
1063 
1064 	return res;
1065 }
1066 
1067 /*
1068  *---------------------------------------------------------------------
1069  * Convert ELAPSED years/months/days of gregorian calendar to elapsed
1070  * days in year.
1071  *
1072  * Note: This will give the true difference to the start of the given year,
1073  * even if months & days are off-scale.
1074  *---------------------------------------------------------------------
1075  */
1076 int32_t
1077 ntpcal_edate_to_yeardays(
1078 	int32_t years,
1079 	int32_t mons,
1080 	int32_t mdays
1081 	)
1082 {
1083 	ntpcal_split tmp;
1084 
1085 	if (0 <= mons && mons < 12) {
1086 		years += 1;
1087 		mdays += real_month_table[is_leapyear(years)][mons];
1088 	} else {
1089 		tmp = ntpcal_days_in_months(mons);
1090 		mdays += tmp.lo
1091 		       + ntpcal_days_in_years(years + tmp.hi)
1092 		       - ntpcal_days_in_years(years);
1093 	}
1094 
1095 	return mdays;
1096 }
1097 
1098 /*
1099  *---------------------------------------------------------------------
1100  * Convert elapsed days and the hour/minute/second information into
1101  * total seconds.
1102  *
1103  * If 'isvalid' is not NULL, do a range check on the time specification
1104  * and tell if the time input is in the normal range, permitting for a
1105  * single leapsecond.
1106  *---------------------------------------------------------------------
1107  */
1108 int32_t
1109 ntpcal_etime_to_seconds(
1110 	int32_t hours,
1111 	int32_t minutes,
1112 	int32_t seconds
1113 	)
1114 {
1115 	int32_t res;
1116 
1117 	res = (hours * MINSPERHR + minutes) * SECSPERMIN + seconds;
1118 
1119 	return res;
1120 }
1121 
1122 /*
1123  *---------------------------------------------------------------------
1124  * Convert the date part of a 'struct tm' (that is, year, month,
1125  * day-of-month) into the RD of that day.
1126  *---------------------------------------------------------------------
1127  */
1128 int32_t
1129 ntpcal_tm_to_rd(
1130 	const struct tm *utm
1131 	)
1132 {
1133 	return ntpcal_edate_to_eradays(utm->tm_year + 1899,
1134 				       utm->tm_mon,
1135 				       utm->tm_mday - 1) + 1;
1136 }
1137 
1138 /*
1139  *---------------------------------------------------------------------
1140  * Convert the date part of a 'struct calendar' (that is, year, month,
1141  * day-of-month) into the RD of that day.
1142  *---------------------------------------------------------------------
1143  */
1144 int32_t
1145 ntpcal_date_to_rd(
1146 	const struct calendar *jd
1147 	)
1148 {
1149 	return ntpcal_edate_to_eradays((int32_t)jd->year - 1,
1150 				       (int32_t)jd->month - 1,
1151 				       (int32_t)jd->monthday - 1) + 1;
1152 }
1153 
1154 /*
1155  *---------------------------------------------------------------------
1156  * convert a year number to rata die of year start
1157  *---------------------------------------------------------------------
1158  */
1159 int32_t
1160 ntpcal_year_to_ystart(
1161 	int32_t year
1162 	)
1163 {
1164 	return ntpcal_days_in_years(year - 1) + 1;
1165 }
1166 
1167 /*
1168  *---------------------------------------------------------------------
1169  * For a given RD, get the RD of the associated year start,
1170  * that is, the RD of the last January,1st on or before that day.
1171  *---------------------------------------------------------------------
1172  */
1173 int32_t
1174 ntpcal_rd_to_ystart(
1175 	int32_t rd
1176 	)
1177 {
1178 	/*
1179 	 * Rather simple exercise: split the day number into elapsed
1180 	 * years and elapsed days, then remove the elapsed days from the
1181 	 * input value. Nice'n sweet...
1182 	 */
1183 	return rd - ntpcal_split_eradays(rd - 1, NULL).lo;
1184 }
1185 
1186 /*
1187  *---------------------------------------------------------------------
1188  * For a given RD, get the RD of the associated month start.
1189  *---------------------------------------------------------------------
1190  */
1191 int32_t
1192 ntpcal_rd_to_mstart(
1193 	int32_t rd
1194 	)
1195 {
1196 	ntpcal_split split;
1197 	int	     leaps;
1198 
1199 	split = ntpcal_split_eradays(rd - 1, &leaps);
1200 	split = ntpcal_split_yeardays(split.lo, leaps);
1201 
1202 	return rd - split.lo;
1203 }
1204 
1205 /*
1206  *---------------------------------------------------------------------
1207  * take a 'struct calendar' and get the seconds-of-day from it.
1208  *---------------------------------------------------------------------
1209  */
1210 int32_t
1211 ntpcal_date_to_daysec(
1212 	const struct calendar *jd
1213 	)
1214 {
1215 	return ntpcal_etime_to_seconds(jd->hour, jd->minute,
1216 				       jd->second);
1217 }
1218 
1219 /*
1220  *---------------------------------------------------------------------
1221  * take a 'struct tm' and get the seconds-of-day from it.
1222  *---------------------------------------------------------------------
1223  */
1224 int32_t
1225 ntpcal_tm_to_daysec(
1226 	const struct tm *utm
1227 	)
1228 {
1229 	return ntpcal_etime_to_seconds(utm->tm_hour, utm->tm_min,
1230 				       utm->tm_sec);
1231 }
1232 
1233 /*
1234  *---------------------------------------------------------------------
1235  * take a 'struct calendar' and convert it to a 'time_t'
1236  *---------------------------------------------------------------------
1237  */
1238 time_t
1239 ntpcal_date_to_time(
1240 	const struct calendar *jd
1241 	)
1242 {
1243 	vint64  join;
1244 	int32_t days, secs;
1245 
1246 	days = ntpcal_date_to_rd(jd) - DAY_UNIX_STARTS;
1247 	secs = ntpcal_date_to_daysec(jd);
1248 	join = ntpcal_dayjoin(days, secs);
1249 
1250 	return vint64_to_time(&join);
1251 }
1252 
1253 
1254 /*
1255  * ==================================================================
1256  *
1257  * extended and unchecked variants of caljulian/caltontp
1258  *
1259  * ==================================================================
1260  */
1261 int
1262 ntpcal_ntp_to_date(
1263 	struct calendar *jd,
1264 	uint32_t	 ntp,
1265 	const time_t	*piv
1266 	)
1267 {
1268 	vint64	     vl;
1269 	ntpcal_split ds;
1270 
1271 	/*
1272 	 * Unfold ntp time around current time into NTP domain. Split
1273 	 * into days and seconds, shift days into CE domain and
1274 	 * process the parts.
1275 	 */
1276 	vl = ntpcal_ntp_to_ntp(ntp, piv);
1277 	ds = ntpcal_daysplit(&vl);
1278 	ds.hi += ntpcal_daysec_to_date(jd, ds.lo);
1279 
1280 	return ntpcal_rd_to_date(jd, ds.hi + DAY_NTP_STARTS);
1281 }
1282 
1283 
1284 uint32_t
1285 ntpcal_date_to_ntp(
1286 	const struct calendar *jd
1287 	)
1288 {
1289 	/*
1290 	 * Convert date to NTP. Ignore yearday, use d/m/y only.
1291 	 */
1292 	return ntpcal_dayjoin(ntpcal_date_to_rd(jd) - DAY_NTP_STARTS,
1293 			      ntpcal_date_to_daysec(jd)).d_s.lo;
1294 }
1295 
1296 /*
1297  * ==================================================================
1298  *
1299  * day-of-week calculations
1300  *
1301  * ==================================================================
1302  */
1303 /*
1304  * Given a RataDie and a day-of-week, calculate a RDN that is reater-than,
1305  * greater-or equal, closest, less-or-equal or less-than the given RDN
1306  * and denotes the given day-of-week
1307  */
1308 int32_t
1309 ntpcal_weekday_gt(
1310 	int32_t rdn,
1311 	int32_t dow
1312 	)
1313 {
1314 	return ntpcal_periodic_extend(rdn+1, dow, 7);
1315 }
1316 
1317 int32_t
1318 ntpcal_weekday_ge(
1319 	int32_t rdn,
1320 	int32_t dow
1321 	)
1322 {
1323 	return ntpcal_periodic_extend(rdn, dow, 7);
1324 }
1325 
1326 int32_t
1327 ntpcal_weekday_close(
1328 	int32_t rdn,
1329 	int32_t dow
1330 	)
1331 {
1332 	return ntpcal_periodic_extend(rdn-3, dow, 7);
1333 }
1334 
1335 int32_t
1336 ntpcal_weekday_le(
1337 	int32_t rdn,
1338 	int32_t dow
1339 	)
1340 {
1341 	return ntpcal_periodic_extend(rdn, dow, -7);
1342 }
1343 
1344 int32_t
1345 ntpcal_weekday_lt(
1346 	int32_t rdn,
1347 	int32_t dow
1348 	)
1349 {
1350 	return ntpcal_periodic_extend(rdn-1, dow, -7);
1351 }
1352 
1353 /*
1354  * ==================================================================
1355  *
1356  * ISO week-calendar conversions
1357  *
1358  * The ISO8601 calendar defines a calendar of years, weeks and weekdays.
1359  * It is related to the Gregorian calendar, and a ISO year starts at the
1360  * Monday closest to Jan,1st of the corresponding Gregorian year.  A ISO
1361  * calendar year has always 52 or 53 weeks, and like the Grogrian
1362  * calendar the ISO8601 calendar repeats itself every 400 years, or
1363  * 146097 days, or 20871 weeks.
1364  *
1365  * While it is possible to write ISO calendar functions based on the
1366  * Gregorian calendar functions, the following implementation takes a
1367  * different approach, based directly on years and weeks.
1368  *
1369  * Analysis of the tabulated data shows that it is not possible to
1370  * interpolate from years to weeks over a full 400 year range; cyclic
1371  * shifts over 400 years do not provide a solution here. But it *is*
1372  * possible to interpolate over every single century of the 400-year
1373  * cycle. (The centennial leap year rule seems to be the culprit here.)
1374  *
1375  * It can be shown that a conversion from years to weeks can be done
1376  * using a linear transformation of the form
1377  *
1378  *   w = floor( y * a + b )
1379  *
1380  * where the slope a must hold to
1381  *
1382  *  52.1780821918 <= a < 52.1791044776
1383  *
1384  * and b must be chosen according to the selected slope and the number
1385  * of the century in a 400-year period.
1386  *
1387  * The inverse calculation can also be done in this way. Careful scaling
1388  * provides an unlimited set of integer coefficients a,k,b that enable
1389  * us to write the calulation in the form
1390  *
1391  *   w = (y * a	 + b ) / k
1392  *   y = (w * a' + b') / k'
1393  *
1394  * In this implementation the values of k and k' are chosen to be
1395  * smallest possible powers of two, so the division can be implemented
1396  * as shifts if the optimiser chooses to do so.
1397  *
1398  * ==================================================================
1399  */
1400 
1401 /*
1402  * Given a number of elapsed (ISO-)years since the begin of the
1403  * christian era, return the number of elapsed weeks corresponding to
1404  * the number of years.
1405  */
1406 int32_t
1407 isocal_weeks_in_years(
1408 	int32_t years
1409 	)
1410 {
1411 	/*
1412 	 * use: w = (y * 53431 + b[c]) / 1024 as interpolation
1413 	 */
1414 	static const int32_t bctab[4] = { 449, 157, 889, 597 };
1415 	int32_t cycle; /* full gregorian cycle */
1416 	int32_t cents; /* full centuries	   */
1417 	int32_t weeks; /* accumulated weeks	   */
1418 
1419 	/* split off full calendar cycles, using floor division */
1420 	cycle = years / 400;
1421 	years = years % 400;
1422 	if (years < 0) {
1423 		cycle -= 1;
1424 		years += 400;
1425 	}
1426 
1427 	/* split off full centuries */
1428 	cents = years / 100;
1429 	years = years % 100;
1430 
1431 	/*
1432 	 * calculate elapsed weeks, taking into account that the
1433 	 * first, third and fourth century have 5218 weeks but the
1434 	 * second century falls short by one week.
1435 	 */
1436 	weeks = (years * 53431 + bctab[cents]) / 1024;
1437 
1438 	return cycle * GREGORIAN_CYCLE_WEEKS
1439 	     + cents * 5218 - (cents > 1)
1440 	     + weeks;
1441 }
1442 
1443 /*
1444  * Given a number of elapsed weeks since the begin of the christian
1445  * era, split this number into the number of elapsed years in res.hi
1446  * and the excessive number of weeks in res.lo. (That is, res.lo is
1447  * the number of elapsed weeks in the remaining partial year.)
1448  */
1449 ntpcal_split
1450 isocal_split_eraweeks(
1451 	int32_t weeks
1452 	)
1453 {
1454 	/*
1455 	 * use: y = (w * 157 + b[c]) / 8192 as interpolation
1456 	 */
1457 	static const int32_t bctab[4] = { 85, 131, 17, 62 };
1458 	ntpcal_split res;
1459 	int32_t	     cents;
1460 
1461 	/*
1462 	 * split off 400-year cycles, using the fact that a 400-year
1463 	 * cycle has 146097 days, which is exactly 20871 weeks.
1464 	 */
1465 	res.hi = weeks / GREGORIAN_CYCLE_WEEKS;
1466 	res.lo = weeks % GREGORIAN_CYCLE_WEEKS;
1467 	if (res.lo < 0) {
1468 		res.hi -= 1;
1469 		res.lo += GREGORIAN_CYCLE_WEEKS;
1470 	}
1471 	res.hi *= 400;
1472 
1473 	/*
1474 	 * split off centuries, taking into account that the first,
1475 	 * third and fourth century have 5218 weeks but that the
1476 	 * second century falls short by one week.
1477 	 */
1478 	res.lo += (res.lo >= 10435);
1479 	cents	= res.lo / 5218;
1480 	res.lo %= 5218;		/* res.lo is weeks in century now */
1481 
1482 	/* convert elapsed weeks in century to elapsed years and weeks */
1483 	res.lo	= res.lo * 157 + bctab[cents];
1484 	res.hi += cents * 100 + res.lo / 8192;
1485 	res.lo	= (res.lo % 8192) / 157;
1486 
1487 	return res;
1488 }
1489 
1490 /*
1491  * Given a second in the NTP time scale and a pivot, expand the NTP
1492  * time stamp around the pivot and convert into an ISO calendar time
1493  * stamp.
1494  */
1495 int
1496 isocal_ntp_to_date(
1497 	struct isodate *id,
1498 	uint32_t		ntp,
1499 	const time_t   *piv
1500 	)
1501 {
1502 	vint64	     vl;
1503 	ntpcal_split ds;
1504 	int32_t      ts[3];
1505 
1506 	/*
1507 	 * Unfold ntp time around current time into NTP domain. Split
1508 	 * into days and seconds, shift days into CE domain and
1509 	 * process the parts.
1510 	 */
1511 	vl = ntpcal_ntp_to_ntp(ntp, piv);
1512 	ds = ntpcal_daysplit(&vl);
1513 
1514 	/* split time part */
1515 	ds.hi += priv_timesplit(ts, ds.lo);
1516 	id->hour   = (uint8_t)ts[0];
1517 	id->minute = (uint8_t)ts[1];
1518 	id->second = (uint8_t)ts[2];
1519 
1520 	/* split date part */
1521 	ds.lo = ds.hi + DAY_NTP_STARTS - 1;	/* elapsed era days  */
1522 	ds.hi = ds.lo / 7;			/* elapsed era weeks */
1523 	ds.lo = ds.lo % 7;			/* elapsed week days */
1524 	if (ds.lo < 0) {			/* floor division!   */
1525 		ds.hi -= 1;
1526 		ds.lo += 7;
1527 	}
1528 	id->weekday = (uint8_t)ds.lo + 1;	/* weekday result    */
1529 
1530 	ds = isocal_split_eraweeks(ds.hi);	/* elapsed years&week*/
1531 	id->year = (uint16_t)ds.hi + 1;		/* shift to current  */
1532 	id->week = (uint8_t )ds.lo + 1;
1533 
1534 	return (ds.hi >= 0 && ds.hi < 0x0000FFFF);
1535 }
1536 
1537 /*
1538  * Convert a ISO date spec into a second in the NTP time scale,
1539  * properly truncated to 32 bit.
1540  */
1541 uint32_t
1542 isocal_date_to_ntp(
1543 	const struct isodate *id
1544 	)
1545 {
1546 	int32_t weeks, days, secs;
1547 
1548 	weeks = isocal_weeks_in_years((int32_t)id->year - 1)
1549 	      + (int32_t)id->week - 1;
1550 	days = weeks * 7 + (int32_t)id->weekday;
1551 	/* days is RDN of ISO date now */
1552 	secs = ntpcal_etime_to_seconds(id->hour, id->minute, id->second);
1553 
1554 	return ntpcal_dayjoin(days - DAY_NTP_STARTS, secs).d_s.lo;
1555 }
1556 
1557 /* -*-EOF-*- */
1558