1275970Scy/*
2275970Scy * ntp_calendar.c - calendar and helper functions
3275970Scy *
4275970Scy * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
5275970Scy * The contents of 'html/copyright.html' apply.
6289764Sglebius *
7289764Sglebius * --------------------------------------------------------------------
8289764Sglebius * Some notes on the implementation:
9289764Sglebius *
10289764Sglebius * Calendar algorithms thrive on the division operation, which is one of
11289764Sglebius * the slowest numerical operations in any CPU. What saves us here from
12289764Sglebius * abysmal performance is the fact that all divisions are divisions by
13289764Sglebius * constant numbers, and most compilers can do this by a multiplication
14289764Sglebius * operation.  But this might not work when using the div/ldiv/lldiv
15289764Sglebius * function family, because many compilers are not able to do inline
16289764Sglebius * expansion of the code with following optimisation for the
17289764Sglebius * constant-divider case.
18289764Sglebius *
19289764Sglebius * Also div/ldiv/lldiv are defined in terms of int/long/longlong, which
20289764Sglebius * are inherently target dependent. Nothing that could not be cured with
21289764Sglebius * autoconf, but still a mess...
22289764Sglebius *
23289764Sglebius * Furthermore, we need floor division in many places. C either leaves
24289764Sglebius * the division behaviour undefined (< C99) or demands truncation to
25289764Sglebius * zero (>= C99), so additional steps are required to make sure the
26289764Sglebius * algorithms work. The {l,ll}div function family is requested to
27289764Sglebius * truncate towards zero, which is also the wrong direction for our
28289764Sglebius * purpose.
29289764Sglebius *
30289764Sglebius * For all this, all divisions by constant are coded manually, even when
31289764Sglebius * there is a joined div/mod operation: The optimiser should sort that
32289764Sglebius * out, if possible. Most of the calculations are done with unsigned
33289764Sglebius * types, explicitely using two's complement arithmetics where
34289764Sglebius * necessary. This minimises the dependecies to compiler and target,
35289764Sglebius * while still giving reasonable to good performance.
36289764Sglebius *
37289764Sglebius * The implementation uses a few tricks that exploit properties of the
38289764Sglebius * two's complement: Floor division on negative dividents can be
39289764Sglebius * executed by using the one's complement of the divident. One's
40289764Sglebius * complement can be easily created using XOR and a mask.
41289764Sglebius *
42289764Sglebius * Finally, check for overflow conditions is minimal. There are only two
43358659Scy * calculation steps in the whole calendar that potentially suffer from
44358659Scy * an internal overflow, and these are coded in a way that avoids
45358659Scy * it. All other functions do not suffer from internal overflow and
46358659Scy * simply return the result truncated to 32 bits.
47275970Scy */
48289764Sglebius
49275970Scy#include <config.h>
50275970Scy#include <sys/types.h>
51275970Scy
52275970Scy#include "ntp_types.h"
53275970Scy#include "ntp_calendar.h"
54275970Scy#include "ntp_stdlib.h"
55275970Scy#include "ntp_fp.h"
56275970Scy#include "ntp_unixtime.h"
57275970Scy
58358659Scy#include "ntpd.h"
59358659Scy#include "lib_strbuf.h"
60358659Scy
61289764Sglebius/* For now, let's take the conservative approach: if the target property
62289764Sglebius * macros are not defined, check a few well-known compiler/architecture
63289764Sglebius * settings. Default is to assume that the representation of signed
64289764Sglebius * integers is unknown and shift-arithmetic-right is not available.
65289764Sglebius */
66289764Sglebius#ifndef TARGET_HAS_2CPL
67289764Sglebius# if defined(__GNUC__)
68289764Sglebius#  if defined(__i386__) || defined(__x86_64__) || defined(__arm__)
69289764Sglebius#   define TARGET_HAS_2CPL 1
70289764Sglebius#  else
71289764Sglebius#   define TARGET_HAS_2CPL 0
72289764Sglebius#  endif
73289764Sglebius# elif defined(_MSC_VER)
74289764Sglebius#  if defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM)
75289764Sglebius#   define TARGET_HAS_2CPL 1
76289764Sglebius#  else
77289764Sglebius#   define TARGET_HAS_2CPL 0
78289764Sglebius#  endif
79289764Sglebius# else
80289764Sglebius#  define TARGET_HAS_2CPL 0
81289764Sglebius# endif
82289764Sglebius#endif
83289764Sglebius
84289764Sglebius#ifndef TARGET_HAS_SAR
85289764Sglebius# define TARGET_HAS_SAR 0
86289764Sglebius#endif
87289764Sglebius
88358659Scy#if !defined(HAVE_64BITREGS) && defined(UINT64_MAX) && (SIZE_MAX >= UINT64_MAX)
89358659Scy# define HAVE_64BITREGS
90358659Scy#endif
91358659Scy
92275970Scy/*
93275970Scy *---------------------------------------------------------------------
94275970Scy * replacing the 'time()' function
95309007Sdelphij *---------------------------------------------------------------------
96275970Scy */
97275970Scy
98275970Scystatic systime_func_ptr systime_func = &time;
99275970Scystatic inline time_t now(void);
100275970Scy
101275970Scy
102275970Scysystime_func_ptr
103275970Scyntpcal_set_timefunc(
104275970Scy	systime_func_ptr nfunc
105275970Scy	)
106275970Scy{
107275970Scy	systime_func_ptr res;
108282408Scy
109275970Scy	res = systime_func;
110275970Scy	if (NULL == nfunc)
111275970Scy		nfunc = &time;
112275970Scy	systime_func = nfunc;
113275970Scy
114275970Scy	return res;
115275970Scy}
116275970Scy
117275970Scy
118275970Scystatic inline time_t
119275970Scynow(void)
120275970Scy{
121275970Scy	return (*systime_func)(NULL);
122275970Scy}
123275970Scy
124275970Scy/*
125275970Scy *---------------------------------------------------------------------
126289764Sglebius * Get sign extension mask and unsigned 2cpl rep for a signed integer
127289764Sglebius *---------------------------------------------------------------------
128289764Sglebius */
129289764Sglebius
130289764Sglebiusstatic inline uint32_t
131289764Sglebiusint32_sflag(
132289764Sglebius	const int32_t v)
133289764Sglebius{
134289764Sglebius#   if TARGET_HAS_2CPL && TARGET_HAS_SAR && SIZEOF_INT >= 4
135289764Sglebius
136289764Sglebius	/* Let's assume that shift is the fastest way to get the sign
137289764Sglebius	 * extension of of a signed integer. This might not always be
138289764Sglebius	 * true, though -- On 8bit CPUs or machines without barrel
139289764Sglebius	 * shifter this will kill the performance. So we make sure
140289764Sglebius	 * we do this only if 'int' has at least 4 bytes.
141289764Sglebius	 */
142289764Sglebius	return (uint32_t)(v >> 31);
143358659Scy
144289764Sglebius#   else
145289764Sglebius
146289764Sglebius	/* This should be a rather generic approach for getting a sign
147289764Sglebius	 * extension mask...
148289764Sglebius	 */
149289764Sglebius	return UINT32_C(0) - (uint32_t)(v < 0);
150289764Sglebius
151289764Sglebius#   endif
152289764Sglebius}
153289764Sglebius
154289764Sglebiusstatic inline int32_t
155289764Sglebiusuint32_2cpl_to_int32(
156289764Sglebius	const uint32_t vu)
157289764Sglebius{
158289764Sglebius	int32_t v;
159358659Scy
160289764Sglebius#   if TARGET_HAS_2CPL
161289764Sglebius
162289764Sglebius	/* Just copy through the 32 bits from the unsigned value if
163289764Sglebius	 * we're on a two's complement target.
164289764Sglebius	 */
165289764Sglebius	v = (int32_t)vu;
166289764Sglebius
167289764Sglebius#   else
168289764Sglebius
169289764Sglebius	/* Convert to signed integer, making sure signed integer
170289764Sglebius	 * overflow cannot happen. Again, the optimiser might or might
171289764Sglebius	 * not find out that this is just a copy of 32 bits on a target
172289764Sglebius	 * with two's complement representation for signed integers.
173289764Sglebius	 */
174289764Sglebius	if (vu > INT32_MAX)
175289764Sglebius		v = -(int32_t)(~vu) - 1;
176289764Sglebius	else
177289764Sglebius		v = (int32_t)vu;
178358659Scy
179289764Sglebius#   endif
180358659Scy
181289764Sglebius	return v;
182289764Sglebius}
183289764Sglebius
184289764Sglebius/*
185289764Sglebius *---------------------------------------------------------------------
186275970Scy * Convert between 'time_t' and 'vint64'
187275970Scy *---------------------------------------------------------------------
188275970Scy */
189275970Scyvint64
190275970Scytime_to_vint64(
191275970Scy	const time_t * ptt
192275970Scy	)
193275970Scy{
194275970Scy	vint64 res;
195275970Scy	time_t tt;
196275970Scy
197275970Scy	tt = *ptt;
198275970Scy
199289764Sglebius#   if SIZEOF_TIME_T <= 4
200275970Scy
201275970Scy	res.D_s.hi = 0;
202275970Scy	if (tt < 0) {
203275970Scy		res.D_s.lo = (uint32_t)-tt;
204275970Scy		M_NEG(res.D_s.hi, res.D_s.lo);
205275970Scy	} else {
206275970Scy		res.D_s.lo = (uint32_t)tt;
207275970Scy	}
208275970Scy
209289764Sglebius#   elif defined(HAVE_INT64)
210275970Scy
211275970Scy	res.q_s = tt;
212275970Scy
213289764Sglebius#   else
214275970Scy	/*
215275970Scy	 * shifting negative signed quantities is compiler-dependent, so
216275970Scy	 * we better avoid it and do it all manually. And shifting more
217275970Scy	 * than the width of a quantity is undefined. Also a don't do!
218275970Scy	 */
219275970Scy	if (tt < 0) {
220275970Scy		tt = -tt;
221275970Scy		res.D_s.lo = (uint32_t)tt;
222275970Scy		res.D_s.hi = (uint32_t)(tt >> 32);
223275970Scy		M_NEG(res.D_s.hi, res.D_s.lo);
224275970Scy	} else {
225275970Scy		res.D_s.lo = (uint32_t)tt;
226275970Scy		res.D_s.hi = (uint32_t)(tt >> 32);
227275970Scy	}
228275970Scy
229289764Sglebius#   endif
230275970Scy
231275970Scy	return res;
232275970Scy}
233275970Scy
234275970Scy
235275970Scytime_t
236275970Scyvint64_to_time(
237275970Scy	const vint64 *tv
238275970Scy	)
239275970Scy{
240275970Scy	time_t res;
241275970Scy
242289764Sglebius#   if SIZEOF_TIME_T <= 4
243275970Scy
244275970Scy	res = (time_t)tv->D_s.lo;
245275970Scy
246289764Sglebius#   elif defined(HAVE_INT64)
247275970Scy
248275970Scy	res = (time_t)tv->q_s;
249275970Scy
250289764Sglebius#   else
251275970Scy
252275970Scy	res = ((time_t)tv->d_s.hi << 32) | tv->D_s.lo;
253275970Scy
254289764Sglebius#   endif
255275970Scy
256275970Scy	return res;
257282408Scy}
258275970Scy
259275970Scy/*
260275970Scy *---------------------------------------------------------------------
261275970Scy * Get the build date & time
262275970Scy *---------------------------------------------------------------------
263275970Scy */
264275970Scyint
265275970Scyntpcal_get_build_date(
266275970Scy	struct calendar * jd
267275970Scy	)
268275970Scy{
269275970Scy	/* The C standard tells us the format of '__DATE__':
270275970Scy	 *
271275970Scy	 * __DATE__ The date of translation of the preprocessing
272275970Scy	 * translation unit: a character string literal of the form "Mmm
273275970Scy	 * dd yyyy", where the names of the months are the same as those
274275970Scy	 * generated by the asctime function, and the first character of
275275970Scy	 * dd is a space character if the value is less than 10. If the
276275970Scy	 * date of translation is not available, an
277275970Scy	 * implementation-defined valid date shall be supplied.
278275970Scy	 *
279275970Scy	 * __TIME__ The time of translation of the preprocessing
280275970Scy	 * translation unit: a character string literal of the form
281275970Scy	 * "hh:mm:ss" as in the time generated by the asctime
282275970Scy	 * function. If the time of translation is not available, an
283275970Scy	 * implementation-defined valid time shall be supplied.
284275970Scy	 *
285275970Scy	 * Note that MSVC declares DATE and TIME to be in the local time
286275970Scy	 * zone, while neither the C standard nor the GCC docs make any
287275970Scy	 * statement about this. As a result, we may be +/-12hrs off
288358659Scy	 * UTC.	 But for practical purposes, this should not be a
289275970Scy	 * problem.
290275970Scy	 *
291275970Scy	 */
292289764Sglebius#   ifdef MKREPRO_DATE
293280849Scy	static const char build[] = MKREPRO_TIME "/" MKREPRO_DATE;
294289764Sglebius#   else
295275970Scy	static const char build[] = __TIME__ "/" __DATE__;
296289764Sglebius#   endif
297275970Scy	static const char mlist[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
298275970Scy
299275970Scy	char		  monstr[4];
300275970Scy	const char *	  cp;
301275970Scy	unsigned short	  hour, minute, second, day, year;
302358659Scy	/* Note: The above quantities are used for sscanf 'hu' format,
303275970Scy	 * so using 'uint16_t' is contra-indicated!
304275970Scy	 */
305275970Scy
306289764Sglebius#   ifdef DEBUG
307358659Scy	static int	  ignore  = 0;
308289764Sglebius#   endif
309282408Scy
310275970Scy	ZERO(*jd);
311275970Scy	jd->year     = 1970;
312275970Scy	jd->month    = 1;
313275970Scy	jd->monthday = 1;
314275970Scy
315289764Sglebius#   ifdef DEBUG
316275970Scy	/* check environment if build date should be ignored */
317275970Scy	if (0 == ignore) {
318275970Scy	    const char * envstr;
319275970Scy	    envstr = getenv("NTPD_IGNORE_BUILD_DATE");
320275970Scy	    ignore = 1 + (envstr && (!*envstr || !strcasecmp(envstr, "yes")));
321275970Scy	}
322275970Scy	if (ignore > 1)
323275970Scy	    return FALSE;
324289764Sglebius#   endif
325275970Scy
326275970Scy	if (6 == sscanf(build, "%hu:%hu:%hu/%3s %hu %hu",
327275970Scy			&hour, &minute, &second, monstr, &day, &year)) {
328275970Scy		cp = strstr(mlist, monstr);
329275970Scy		if (NULL != cp) {
330275970Scy			jd->year     = year;
331275970Scy			jd->month    = (uint8_t)((cp - mlist) / 3 + 1);
332275970Scy			jd->monthday = (uint8_t)day;
333275970Scy			jd->hour     = (uint8_t)hour;
334275970Scy			jd->minute   = (uint8_t)minute;
335275970Scy			jd->second   = (uint8_t)second;
336275970Scy
337275970Scy			return TRUE;
338275970Scy		}
339275970Scy	}
340275970Scy
341275970Scy	return FALSE;
342275970Scy}
343275970Scy
344275970Scy
345275970Scy/*
346275970Scy *---------------------------------------------------------------------
347275970Scy * basic calendar stuff
348309007Sdelphij *---------------------------------------------------------------------
349275970Scy */
350275970Scy
351275970Scy/*
352275970Scy * Some notes on the terminology:
353275970Scy *
354275970Scy * We use the proleptic Gregorian calendar, which is the Gregorian
355275970Scy * calendar extended in both directions ad infinitum. This totally
356275970Scy * disregards the fact that this calendar was invented in 1582, and
357275970Scy * was adopted at various dates over the world; sometimes even after
358275970Scy * the start of the NTP epoch.
359275970Scy *
360275970Scy * Normally date parts are given as current cycles, while time parts
361275970Scy * are given as elapsed cycles:
362275970Scy *
363275970Scy * 1970-01-01/03:04:05 means 'IN the 1970st. year, IN the first month,
364275970Scy * ON the first day, with 3hrs, 4minutes and 5 seconds elapsed.
365275970Scy *
366275970Scy * The basic calculations for this calendar implementation deal with
367275970Scy * ELAPSED date units, which is the number of full years, full months
368275970Scy * and full days before a date: 1970-01-01 would be (1969, 0, 0) in
369275970Scy * that notation.
370275970Scy *
371275970Scy * To ease the numeric computations, month and day values outside the
372275970Scy * normal range are acceptable: 2001-03-00 will be treated as the day
373275970Scy * before 2001-03-01, 2000-13-32 will give the same result as
374275970Scy * 2001-02-01 and so on.
375275970Scy *
376275970Scy * 'rd' or 'RD' is used as an abbreviation for the latin 'rata die'
377275970Scy * (day number).  This is the number of days elapsed since 0000-12-31
378275970Scy * in the proleptic Gregorian calendar. The begin of the Christian Era
379275970Scy * (0001-01-01) is RD(1).
380275970Scy */
381275970Scy
382275970Scy/*
383309007Sdelphij * ====================================================================
384275970Scy *
385275970Scy * General algorithmic stuff
386275970Scy *
387309007Sdelphij * ====================================================================
388275970Scy */
389275970Scy
390275970Scy/*
391275970Scy *---------------------------------------------------------------------
392358659Scy * fast modulo 7 operations (floor/mathematical convention)
393358659Scy *---------------------------------------------------------------------
394358659Scy */
395358659Scyint
396358659Scyu32mod7(
397358659Scy	uint32_t x
398358659Scy	)
399358659Scy{
400358659Scy	/* This is a combination of tricks from "Hacker's Delight" with
401358659Scy	 * some modifications, like a multiplication that rounds up to
402358659Scy	 * drop the final adjustment stage.
403358659Scy	 *
404358659Scy	 * Do a partial reduction by digit sum to keep the value in the
405358659Scy	 * range permitted for the mul/shift stage. There are several
406358659Scy	 * possible and absolutely equivalent shift/mask combinations;
407358659Scy	 * this one is ARM-friendly because of a mask that fits into 16
408358659Scy	 * bit.
409358659Scy	 */
410358659Scy	x = (x >> 15) + (x & UINT32_C(0x7FFF));
411358659Scy	/* Take reminder as (mod 8) by mul/shift. Since the multiplier
412358659Scy	 * was calculated using ceil() instead of floor(), it skips the
413358659Scy	 * value '7' properly.
414358659Scy	 *    M <- ceil(ldexp(8/7, 29))
415358659Scy	 */
416358659Scy	return (int)((x * UINT32_C(0x24924925)) >> 29);
417358659Scy}
418358659Scy
419358659Scyint
420358659Scyi32mod7(
421358659Scy	int32_t x
422358659Scy	)
423358659Scy{
424358659Scy	/* We add (2**32 - 2**32 % 7), which is (2**32 - 4), to negative
425358659Scy	 * numbers to map them into the postive range. Only the term '-4'
426358659Scy	 * survives, obviously.
427358659Scy	 */
428358659Scy	uint32_t ux = (uint32_t)x;
429358659Scy	return u32mod7((x < 0) ? (ux - 4u) : ux);
430358659Scy}
431358659Scy
432358659Scyuint32_t
433358659Scyi32fmod(
434358659Scy	int32_t	 x,
435358659Scy	uint32_t d
436358659Scy	)
437358659Scy{
438358659Scy	uint32_t ux = (uint32_t)x;
439358659Scy	uint32_t sf = UINT32_C(0) - (x < 0);
440358659Scy	ux = (sf ^ ux ) % d;
441358659Scy	return (d & sf) + (sf ^ ux);
442358659Scy}
443358659Scy
444358659Scy/*
445358659Scy *---------------------------------------------------------------------
446275970Scy * Do a periodic extension of 'value' around 'pivot' with a period of
447275970Scy * 'cycle'.
448275970Scy *
449275970Scy * The result 'res' is a number that holds to the following properties:
450275970Scy *
451275970Scy *   1)	 res MOD cycle == value MOD cycle
452275970Scy *   2)	 pivot <= res < pivot + cycle
453275970Scy *	 (replace </<= with >/>= for negative cycles)
454275970Scy *
455275970Scy * where 'MOD' denotes the modulo operator for FLOOR DIVISION, which
456275970Scy * is not the same as the '%' operator in C: C requires division to be
457275970Scy * a truncated division, where remainder and dividend have the same
458275970Scy * sign if the remainder is not zero, whereas floor division requires
459275970Scy * divider and modulus to have the same sign for a non-zero modulus.
460275970Scy *
461275970Scy * This function has some useful applications:
462275970Scy *
463275970Scy * + let Y be a calendar year and V a truncated 2-digit year: then
464275970Scy *	periodic_extend(Y-50, V, 100)
465275970Scy *   is the closest expansion of the truncated year with respect to
466275970Scy *   the full year, that is a 4-digit year with a difference of less
467275970Scy *   than 50 years to the year Y. ("century unfolding")
468275970Scy *
469275970Scy * + let T be a UN*X time stamp and V be seconds-of-day: then
470275970Scy *	perodic_extend(T-43200, V, 86400)
471275970Scy *   is a time stamp that has the same seconds-of-day as the input
472275970Scy *   value, with an absolute difference to T of <= 12hrs.  ("day
473275970Scy *   unfolding")
474275970Scy *
475275970Scy * + Wherever you have a truncated periodic value and a non-truncated
476275970Scy *   base value and you want to match them somehow...
477275970Scy *
478275970Scy * Basically, the function delivers 'pivot + (value - pivot) % cycle',
479275970Scy * but the implementation takes some pains to avoid internal signed
480275970Scy * integer overflows in the '(value - pivot) % cycle' part and adheres
481275970Scy * to the floor division convention.
482275970Scy *
483275970Scy * If 64bit scalars where available on all intended platforms, writing a
484275970Scy * version that uses 64 bit ops would be easy; writing a general
485275970Scy * division routine for 64bit ops on a platform that can only do
486275970Scy * 32/16bit divisions and is still performant is a bit more
487275970Scy * difficult. Since most usecases can be coded in a way that does only
488358659Scy * require the 32bit version a 64bit version is NOT provided here.
489309007Sdelphij *---------------------------------------------------------------------
490275970Scy */
491275970Scyint32_t
492275970Scyntpcal_periodic_extend(
493275970Scy	int32_t pivot,
494275970Scy	int32_t value,
495275970Scy	int32_t cycle
496275970Scy	)
497275970Scy{
498358659Scy	/* Implement a 4-quadrant modulus calculation by 2 2-quadrant
499358659Scy	 * branches, one for positive and one for negative dividers.
500358659Scy	 * Everything else can be handled by bit level logic and
501358659Scy	 * conditional one's complement arithmetic.  By convention, we
502358659Scy	 * assume
503358659Scy	 *
504358659Scy	 * x % b == 0  if  |b| < 2
505358659Scy	 *
506358659Scy	 * that is, we don't actually divide for cycles of -1,0,1 and
507358659Scy	 * return the pivot value in that case.
508358659Scy	 */
509358659Scy	uint32_t	uv = (uint32_t)value;
510358659Scy	uint32_t	up = (uint32_t)pivot;
511358659Scy	uint32_t	uc, sf;
512275970Scy
513358659Scy	if (cycle > 1)
514358659Scy	{
515358659Scy		uc = (uint32_t)cycle;
516358659Scy		sf = UINT32_C(0) - (value < pivot);
517358659Scy
518358659Scy		uv = sf ^ (uv - up);
519358659Scy		uv %= uc;
520358659Scy		pivot += (uc & sf) + (sf ^ uv);
521275970Scy	}
522358659Scy	else if (cycle < -1)
523358659Scy	{
524358659Scy		uc = ~(uint32_t)cycle + 1;
525358659Scy		sf = UINT32_C(0) - (value > pivot);
526358659Scy
527358659Scy		uv = sf ^ (up - uv);
528358659Scy		uv %= uc;
529358659Scy		pivot -= (uc & sf) + (sf ^ uv);
530275970Scy	}
531275970Scy	return pivot;
532275970Scy}
533275970Scy
534309007Sdelphij/*---------------------------------------------------------------------
535309007Sdelphij * Note to the casual reader
536309007Sdelphij *
537309007Sdelphij * In the next two functions you will find (or would have found...)
538309007Sdelphij * the expression
539309007Sdelphij *
540309007Sdelphij *   res.Q_s -= 0x80000000;
541309007Sdelphij *
542309007Sdelphij * There was some ruckus about a possible programming error due to
543309007Sdelphij * integer overflow and sign propagation.
544309007Sdelphij *
545309007Sdelphij * This assumption is based on a lack of understanding of the C
546309007Sdelphij * standard. (Though this is admittedly not one of the most 'natural'
547309007Sdelphij * aspects of the 'C' language and easily to get wrong.)
548309007Sdelphij *
549358659Scy * see
550309007Sdelphij *	http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
551309007Sdelphij *	"ISO/IEC 9899:201x Committee Draft ��� April 12, 2011"
552309007Sdelphij *	6.4.4.1 Integer constants, clause 5
553309007Sdelphij *
554309007Sdelphij * why there is no sign extension/overflow problem here.
555309007Sdelphij *
556309007Sdelphij * But to ease the minds of the doubtful, I added back the 'u' qualifiers
557358659Scy * that somehow got lost over the last years.
558309007Sdelphij */
559309007Sdelphij
560309007Sdelphij
561275970Scy/*
562309007Sdelphij *---------------------------------------------------------------------
563275970Scy * Convert a timestamp in NTP scale to a 64bit seconds value in the UN*X
564275970Scy * scale with proper epoch unfolding around a given pivot or the current
565275970Scy * system time. This function happily accepts negative pivot values as
566358659Scy * timestamps before 1970-01-01, so be aware of possible trouble on
567275970Scy * platforms with 32bit 'time_t'!
568275970Scy *
569275970Scy * This is also a periodic extension, but since the cycle is 2^32 and
570275970Scy * the shift is 2^31, we can do some *very* fast math without explicit
571275970Scy * divisions.
572309007Sdelphij *---------------------------------------------------------------------
573275970Scy */
574275970Scyvint64
575275970Scyntpcal_ntp_to_time(
576275970Scy	uint32_t	ntp,
577275970Scy	const time_t *	pivot
578275970Scy	)
579275970Scy{
580275970Scy	vint64 res;
581275970Scy
582289764Sglebius#   if defined(HAVE_INT64)
583275970Scy
584282408Scy	res.q_s = (pivot != NULL)
585275970Scy		      ? *pivot
586282408Scy		      : now();
587309007Sdelphij	res.Q_s -= 0x80000000u;		/* unshift of half range */
588275970Scy	ntp	-= (uint32_t)JAN_1970;	/* warp into UN*X domain */
589275970Scy	ntp	-= res.D_s.lo;		/* cycle difference	 */
590275970Scy	res.Q_s += (uint64_t)ntp;	/* get expanded time	 */
591275970Scy
592289764Sglebius#   else /* no 64bit scalars */
593282408Scy
594275970Scy	time_t tmp;
595282408Scy
596282408Scy	tmp = (pivot != NULL)
597275970Scy		  ? *pivot
598282408Scy		  : now();
599275970Scy	res = time_to_vint64(&tmp);
600309007Sdelphij	M_SUB(res.D_s.hi, res.D_s.lo, 0, 0x80000000u);
601275970Scy	ntp -= (uint32_t)JAN_1970;	/* warp into UN*X domain */
602275970Scy	ntp -= res.D_s.lo;		/* cycle difference	 */
603275970Scy	M_ADD(res.D_s.hi, res.D_s.lo, 0, ntp);
604275970Scy
605289764Sglebius#   endif /* no 64bit scalars */
606275970Scy
607275970Scy	return res;
608275970Scy}
609275970Scy
610275970Scy/*
611309007Sdelphij *---------------------------------------------------------------------
612275970Scy * Convert a timestamp in NTP scale to a 64bit seconds value in the NTP
613275970Scy * scale with proper epoch unfolding around a given pivot or the current
614275970Scy * system time.
615275970Scy *
616275970Scy * Note: The pivot must be given in the UN*X time domain!
617275970Scy *
618275970Scy * This is also a periodic extension, but since the cycle is 2^32 and
619275970Scy * the shift is 2^31, we can do some *very* fast math without explicit
620275970Scy * divisions.
621309007Sdelphij *---------------------------------------------------------------------
622275970Scy */
623275970Scyvint64
624275970Scyntpcal_ntp_to_ntp(
625275970Scy	uint32_t      ntp,
626275970Scy	const time_t *pivot
627275970Scy	)
628275970Scy{
629275970Scy	vint64 res;
630275970Scy
631289764Sglebius#   if defined(HAVE_INT64)
632275970Scy
633275970Scy	res.q_s = (pivot)
634275970Scy		      ? *pivot
635275970Scy		      : now();
636309007Sdelphij	res.Q_s -= 0x80000000u;		/* unshift of half range */
637275970Scy	res.Q_s += (uint32_t)JAN_1970;	/* warp into NTP domain	 */
638275970Scy	ntp	-= res.D_s.lo;		/* cycle difference	 */
639275970Scy	res.Q_s += (uint64_t)ntp;	/* get expanded time	 */
640275970Scy
641289764Sglebius#   else /* no 64bit scalars */
642282408Scy
643275970Scy	time_t tmp;
644282408Scy
645275970Scy	tmp = (pivot)
646275970Scy		  ? *pivot
647275970Scy		  : now();
648275970Scy	res = time_to_vint64(&tmp);
649275970Scy	M_SUB(res.D_s.hi, res.D_s.lo, 0, 0x80000000u);
650275970Scy	M_ADD(res.D_s.hi, res.D_s.lo, 0, (uint32_t)JAN_1970);/*into NTP */
651275970Scy	ntp -= res.D_s.lo;		/* cycle difference	 */
652275970Scy	M_ADD(res.D_s.hi, res.D_s.lo, 0, ntp);
653275970Scy
654289764Sglebius#   endif /* no 64bit scalars */
655275970Scy
656275970Scy	return res;
657275970Scy}
658275970Scy
659275970Scy
660275970Scy/*
661309007Sdelphij * ====================================================================
662275970Scy *
663275970Scy * Splitting values to composite entities
664275970Scy *
665309007Sdelphij * ====================================================================
666275970Scy */
667275970Scy
668275970Scy/*
669309007Sdelphij *---------------------------------------------------------------------
670275970Scy * Split a 64bit seconds value into elapsed days in 'res.hi' and
671275970Scy * elapsed seconds since midnight in 'res.lo' using explicit floor
672275970Scy * division. This function happily accepts negative time values as
673275970Scy * timestamps before the respective epoch start.
674309007Sdelphij *---------------------------------------------------------------------
675275970Scy */
676275970Scyntpcal_split
677275970Scyntpcal_daysplit(
678275970Scy	const vint64 *ts
679275970Scy	)
680275970Scy{
681275970Scy	ntpcal_split res;
682358659Scy	uint32_t Q, R;
683275970Scy
684358659Scy#   if defined(HAVE_64BITREGS)
685358659Scy
686358659Scy	/* Assume we have 64bit registers an can do a divison by
687358659Scy	 * constant reasonably fast using the one's complement trick..
688289764Sglebius	 */
689358659Scy	uint64_t sf64 = (uint64_t)-(ts->q_s < 0);
690358659Scy	Q = (uint32_t)(sf64 ^ ((sf64 ^ ts->Q_s) / SECSPERDAY));
691358659Scy	R = (uint32_t)(ts->Q_s - Q * SECSPERDAY);
692358659Scy
693358659Scy#   elif defined(UINT64_MAX) && !defined(__arm__)
694358659Scy
695358659Scy	/* We rely on the compiler to do efficient 64bit divisions as
696358659Scy	 * good as possible. Which might or might not be true. At least
697358659Scy	 * for ARM CPUs, the sum-by-digit code in the next section is
698358659Scy	 * faster for many compilers. (This might change over time, but
699358659Scy	 * the 64bit-by-32bit division will never outperform the exact
700358659Scy	 * division by a substantial factor....)
701358659Scy	 */
702289764Sglebius	if (ts->q_s < 0)
703289764Sglebius		Q = ~(uint32_t)(~ts->Q_s / SECSPERDAY);
704289764Sglebius	else
705358659Scy		Q =  (uint32_t)( ts->Q_s / SECSPERDAY);
706358659Scy	R = ts->D_s.lo - Q * SECSPERDAY;
707275970Scy
708289764Sglebius#   else
709275970Scy
710358659Scy	/* We don't have 64bit regs. That hurts a bit.
711289764Sglebius	 *
712358659Scy	 * Here we use a mean trick to get away with just one explicit
713358659Scy	 * modulo operation and pure 32bit ops.
714358659Scy	 *
715358659Scy	 * Remember: 86400 <--> 128 * 675
716358659Scy	 *
717358659Scy	 * So we discard the lowest 7 bit and do an exact division by
718358659Scy	 * 675, modulo 2**32.
719358659Scy	 *
720358659Scy	 * First we shift out the lower 7 bits.
721358659Scy	 *
722358659Scy	 * Then we use a digit-wise pseudo-reduction, where a 'digit' is
723358659Scy	 * actually a 16-bit group. This is followed by a full reduction
724358659Scy	 * with a 'true' division step. This yields the modulus of the
725358659Scy	 * full 64bit value. The sign bit gets some extra treatment.
726358659Scy	 *
727358659Scy	 * Then we decrement the lower limb by that modulus, so it is
728358659Scy	 * exactly divisible by 675. [*]
729358659Scy	 *
730358659Scy	 * Then we multiply with the modular inverse of 675 (mod 2**32)
731358659Scy	 * and voila, we have the result.
732358659Scy	 *
733358659Scy	 * Special Thanks to Henry S. Warren and his "Hacker's delight"
734358659Scy	 * for giving that idea.
735358659Scy	 *
736358659Scy	 * (Note[*]: that's not the full truth. We would have to
737358659Scy	 * subtract the modulus from the full 64 bit number to get a
738358659Scy	 * number that is divisible by 675. But since we use the
739358659Scy	 * multiplicative inverse (mod 2**32) there's no reason to carry
740358659Scy	 * the subtraction into the upper bits!)
741289764Sglebius	 */
742358659Scy	uint32_t al = ts->D_s.lo;
743358659Scy	uint32_t ah = ts->D_s.hi;
744282408Scy
745358659Scy	/* shift out the lower 7 bits, smash sign bit */
746358659Scy	al = (al >> 7) | (ah << 25);
747358659Scy	ah = (ah >> 7) & 0x00FFFFFFu;
748275970Scy
749358659Scy	R  = (ts->d_s.hi < 0) ? 239 : 0;/* sign bit value */
750358659Scy	R += (al & 0xFFFF);
751358659Scy	R += (al >> 16	 ) * 61u;	/* 2**16 % 675 */
752358659Scy	R += (ah & 0xFFFF) * 346u;	/* 2**32 % 675 */
753358659Scy	R += (ah >> 16	 ) * 181u;	/* 2**48 % 675 */
754358659Scy	R %= 675u;			/* final reduction */
755358659Scy	Q  = (al - R) * 0x2D21C10Bu;	/* modinv(675, 2**32) */
756358659Scy	R  = (R << 7) | (ts->d_s.lo & 0x07F);
757275970Scy
758358659Scy#   endif
759358659Scy
760358659Scy	res.hi = uint32_2cpl_to_int32(Q);
761358659Scy	res.lo = R;
762358659Scy
763358659Scy	return res;
764358659Scy}
765358659Scy
766358659Scy/*
767358659Scy *---------------------------------------------------------------------
768358659Scy * Split a 64bit seconds value into elapsed weeks in 'res.hi' and
769358659Scy * elapsed seconds since week start in 'res.lo' using explicit floor
770358659Scy * division. This function happily accepts negative time values as
771358659Scy * timestamps before the respective epoch start.
772358659Scy *---------------------------------------------------------------------
773358659Scy */
774358659Scyntpcal_split
775358659Scyntpcal_weeksplit(
776358659Scy	const vint64 *ts
777358659Scy	)
778358659Scy{
779358659Scy	ntpcal_split res;
780358659Scy	uint32_t Q, R;
781358659Scy
782358659Scy	/* This is a very close relative to the day split function; for
783358659Scy	 * details, see there!
784289764Sglebius	 */
785275970Scy
786358659Scy#   if defined(HAVE_64BITREGS)
787358659Scy
788358659Scy	uint64_t sf64 = (uint64_t)-(ts->q_s < 0);
789358659Scy	Q = (uint32_t)(sf64 ^ ((sf64 ^ ts->Q_s) / SECSPERWEEK));
790358659Scy	R = (uint32_t)(ts->Q_s - Q * SECSPERWEEK);
791358659Scy
792358659Scy#   elif defined(UINT64_MAX) && !defined(__arm__)
793358659Scy
794358659Scy	if (ts->q_s < 0)
795358659Scy		Q = ~(uint32_t)(~ts->Q_s / SECSPERWEEK);
796358659Scy	else
797358659Scy		Q =  (uint32_t)( ts->Q_s / SECSPERWEEK);
798358659Scy	R = ts->D_s.lo - Q * SECSPERWEEK;
799358659Scy
800358659Scy#   else
801358659Scy
802358659Scy	/* Remember: 7*86400 <--> 604800 <--> 128 * 4725 */
803358659Scy	uint32_t al = ts->D_s.lo;
804358659Scy	uint32_t ah = ts->D_s.hi;
805358659Scy
806358659Scy	al = (al >> 7) | (ah << 25);
807358659Scy	ah = (ah >> 7) & 0x00FFFFFF;
808358659Scy
809358659Scy	R  = (ts->d_s.hi < 0) ? 2264 : 0;/* sign bit value */
810358659Scy	R += (al & 0xFFFF);
811358659Scy	R += (al >> 16	 ) * 4111u;	/* 2**16 % 4725 */
812358659Scy	R += (ah & 0xFFFF) * 3721u;	/* 2**32 % 4725 */
813358659Scy	R += (ah >> 16	 ) * 2206u;	/* 2**48 % 4725 */
814358659Scy	R %= 4725u;			/* final reduction */
815358659Scy	Q  = (al - R) * 0x98BBADDDu;	/* modinv(4725, 2**32) */
816358659Scy	R  = (R << 7) | (ts->d_s.lo & 0x07F);
817358659Scy
818289764Sglebius#   endif
819358659Scy
820289764Sglebius	res.hi = uint32_2cpl_to_int32(Q);
821358659Scy	res.lo = R;
822275970Scy
823275970Scy	return res;
824275970Scy}
825275970Scy
826275970Scy/*
827309007Sdelphij *---------------------------------------------------------------------
828275970Scy * Split a 32bit seconds value into h/m/s and excessive days.  This
829275970Scy * function happily accepts negative time values as timestamps before
830275970Scy * midnight.
831309007Sdelphij *---------------------------------------------------------------------
832275970Scy */
833275970Scystatic int32_t
834275970Scypriv_timesplit(
835275970Scy	int32_t split[3],
836275970Scy	int32_t ts
837275970Scy	)
838275970Scy{
839289764Sglebius	/* Do 3 chained floor divisions by positive constants, using the
840289764Sglebius	 * one's complement trick and factoring out the intermediate XOR
841289764Sglebius	 * ops to reduce the number of operations.
842289764Sglebius	 */
843358659Scy	uint32_t us, um, uh, ud, sf32;
844275970Scy
845358659Scy	sf32 = int32_sflag(ts);
846275970Scy
847358659Scy	us = (uint32_t)ts;
848358659Scy	um = (sf32 ^ us) / SECSPERMIN;
849289764Sglebius	uh = um / MINSPERHR;
850289764Sglebius	ud = uh / HRSPERDAY;
851275970Scy
852358659Scy	um ^= sf32;
853358659Scy	uh ^= sf32;
854358659Scy	ud ^= sf32;
855289764Sglebius
856289764Sglebius	split[0] = (int32_t)(uh - ud * HRSPERDAY );
857289764Sglebius	split[1] = (int32_t)(um - uh * MINSPERHR );
858289764Sglebius	split[2] = (int32_t)(us - um * SECSPERMIN);
859358659Scy
860289764Sglebius	return uint32_2cpl_to_int32(ud);
861275970Scy}
862275970Scy
863275970Scy/*
864309007Sdelphij *---------------------------------------------------------------------
865275970Scy * Given the number of elapsed days in the calendar era, split this
866275970Scy * number into the number of elapsed years in 'res.hi' and the number
867275970Scy * of elapsed days of that year in 'res.lo'.
868275970Scy *
869275970Scy * if 'isleapyear' is not NULL, it will receive an integer that is 0 for
870275970Scy * regular years and a non-zero value for leap years.
871275970Scy *---------------------------------------------------------------------
872275970Scy */
873275970Scyntpcal_split
874275970Scyntpcal_split_eradays(
875275970Scy	int32_t days,
876275970Scy	int  *isleapyear
877275970Scy	)
878275970Scy{
879358659Scy	/* Use the fast cycle split algorithm here, to calculate the
880289764Sglebius	 * centuries and years in a century with one division each. This
881289764Sglebius	 * reduces the number of division operations to two, but is
882358659Scy	 * susceptible to internal range overflow. We take some extra
883358659Scy	 * steps to avoid the gap.
884289764Sglebius	 */
885275970Scy	ntpcal_split res;
886289764Sglebius	int32_t	 n100, n001; /* calendar year cycles */
887358659Scy	uint32_t uday, Q;
888282408Scy
889358659Scy	/* split off centuries first
890358659Scy	 *
891358659Scy	 * We want to execute '(days * 4 + 3) /% 146097' under floor
892358659Scy	 * division rules in the first step. Well, actually we want to
893358659Scy	 * calculate 'floor((days + 0.75) / 36524.25)', but we want to
894358659Scy	 * do it in scaled integer calculation.
895358659Scy	 */
896358659Scy#   if defined(HAVE_64BITREGS)
897358659Scy
898358659Scy	/* not too complicated with an intermediate 64bit value */
899358659Scy	uint64_t	ud64, sf64;
900358659Scy	ud64 = ((uint64_t)days << 2) | 3u;
901358659Scy	sf64 = (uint64_t)-(days < 0);
902358659Scy	Q    = (uint32_t)(sf64 ^ ((sf64 ^ ud64) / GREGORIAN_CYCLE_DAYS));
903358659Scy	uday = (uint32_t)(ud64 - Q * GREGORIAN_CYCLE_DAYS);
904289764Sglebius	n100 = uint32_2cpl_to_int32(Q);
905358659Scy
906358659Scy#   else
907358659Scy
908358659Scy	/* '4*days+3' suffers from range overflow when going to the
909358659Scy	 * limits. We solve this by doing an exact division (mod 2^32)
910358659Scy	 * after caclulating the remainder first.
911358659Scy	 *
912358659Scy	 * We start with a partial reduction by digit sums, extracting
913358659Scy	 * the upper bits from the original value before they get lost
914358659Scy	 * by scaling, and do one full division step to get the true
915358659Scy	 * remainder.  Then a final multiplication with the
916358659Scy	 * multiplicative inverse of 146097 (mod 2^32) gives us the full
917358659Scy	 * quotient.
918358659Scy	 *
919358659Scy	 * (-2^33) % 146097	--> 130717    : the sign bit value
920358659Scy	 * ( 2^20) % 146097	--> 25897     : the upper digit value
921358659Scy	 * modinv(146097, 2^32) --> 660721233 : the inverse
922358659Scy	 */
923358659Scy	uint32_t ux = ((uint32_t)days << 2) | 3;
924358659Scy	uday  = (days < 0) ? 130717u : 0u;	    /* sign dgt */
925358659Scy	uday += ((days >> 18) & 0x01FFFu) * 25897u; /* hi dgt (src!) */
926358659Scy	uday += (ux & 0xFFFFFu);		    /* lo dgt */
927358659Scy	uday %= GREGORIAN_CYCLE_DAYS;		    /* full reduction */
928358659Scy	Q     = (ux  - uday) * 660721233u;	    /* exact div */
929358659Scy	n100  = uint32_2cpl_to_int32(Q);
930358659Scy
931358659Scy#   endif
932358659Scy
933289764Sglebius	/* Split off years in century -- days >= 0 here, and we're far
934289764Sglebius	 * away from integer overflow trouble now. */
935289764Sglebius	uday |= 3;
936358659Scy	n001  = uday / GREGORIAN_NORMAL_LEAP_CYCLE_DAYS;
937358659Scy	uday -= n001 * GREGORIAN_NORMAL_LEAP_CYCLE_DAYS;
938282408Scy
939289764Sglebius	/* Assemble the year and day in year */
940289764Sglebius	res.hi = n100 * 100 + n001;
941289764Sglebius	res.lo = uday / 4u;
942289764Sglebius
943358659Scy	/* Possibly set the leap year flag */
944358659Scy	if (isleapyear) {
945358659Scy		uint32_t tc = (uint32_t)n100 + 1;
946358659Scy		uint32_t ty = (uint32_t)n001 + 1;
947358659Scy		*isleapyear = !(ty & 3)
948358659Scy		    && ((ty != 100) || !(tc & 3));
949358659Scy	}
950275970Scy	return res;
951275970Scy}
952275970Scy
953275970Scy/*
954275970Scy *---------------------------------------------------------------------
955275970Scy * Given a number of elapsed days in a year and a leap year indicator,
956275970Scy * split the number of elapsed days into the number of elapsed months in
957275970Scy * 'res.hi' and the number of elapsed days of that month in 'res.lo'.
958275970Scy *
959275970Scy * This function will fail and return {-1,-1} if the number of elapsed
960275970Scy * days is not in the valid range!
961275970Scy *---------------------------------------------------------------------
962275970Scy */
963275970Scyntpcal_split
964275970Scyntpcal_split_yeardays(
965275970Scy	int32_t eyd,
966358659Scy	int	isleap
967275970Scy	)
968275970Scy{
969358659Scy	/* Use the unshifted-year, February-with-30-days approach here.
970358659Scy	 * Fractional interpolations are used in both directions, with
971358659Scy	 * the smallest power-of-two divider to avoid any true division.
972358659Scy	 */
973358659Scy	ntpcal_split	res = {-1, -1};
974275970Scy
975358659Scy	/* convert 'isleap' to number of defective days */
976358659Scy	isleap = 1 + !isleap;
977358659Scy	/* adjust for February of 30 nominal days */
978358659Scy	if (eyd >= 61 - isleap)
979358659Scy		eyd += isleap;
980358659Scy	/* if in range, convert to months and days in month */
981358659Scy	if (eyd >= 0 && eyd < 367) {
982358659Scy		res.hi = (eyd * 67 + 32) >> 11;
983358659Scy		res.lo = eyd - ((489 * res.hi + 8) >> 4);
984275970Scy	}
985275970Scy
986275970Scy	return res;
987275970Scy}
988275970Scy
989275970Scy/*
990275970Scy *---------------------------------------------------------------------
991275970Scy * Convert a RD into the date part of a 'struct calendar'.
992275970Scy *---------------------------------------------------------------------
993275970Scy */
994275970Scyint
995275970Scyntpcal_rd_to_date(
996275970Scy	struct calendar *jd,
997275970Scy	int32_t		 rd
998275970Scy	)
999275970Scy{
1000275970Scy	ntpcal_split split;
1001289764Sglebius	int	     leapy;
1002289764Sglebius	u_int	     ymask;
1003275970Scy
1004358659Scy	/* Get day-of-week first. It's simply the RD (mod 7)... */
1005358659Scy	jd->weekday = i32mod7(rd);
1006275970Scy
1007289764Sglebius	split = ntpcal_split_eradays(rd - 1, &leapy);
1008289764Sglebius	/* Get year and day-of-year, with overflow check. If any of the
1009289764Sglebius	 * upper 16 bits is set after shifting to unity-based years, we
1010289764Sglebius	 * will have an overflow when converting to an unsigned 16bit
1011289764Sglebius	 * year. Shifting to the right is OK here, since it does not
1012289764Sglebius	 * matter if the shift is logic or arithmetic.
1013289764Sglebius	 */
1014289764Sglebius	split.hi += 1;
1015289764Sglebius	ymask = 0u - ((split.hi >> 16) == 0);
1016289764Sglebius	jd->year = (uint16_t)(split.hi & ymask);
1017275970Scy	jd->yearday = (uint16_t)split.lo + 1;
1018275970Scy
1019275970Scy	/* convert to month and mday */
1020289764Sglebius	split = ntpcal_split_yeardays(split.lo, leapy);
1021275970Scy	jd->month    = (uint8_t)split.hi + 1;
1022275970Scy	jd->monthday = (uint8_t)split.lo + 1;
1023275970Scy
1024289764Sglebius	return ymask ? leapy : -1;
1025275970Scy}
1026275970Scy
1027275970Scy/*
1028275970Scy *---------------------------------------------------------------------
1029275970Scy * Convert a RD into the date part of a 'struct tm'.
1030275970Scy *---------------------------------------------------------------------
1031275970Scy */
1032275970Scyint
1033275970Scyntpcal_rd_to_tm(
1034275970Scy	struct tm  *utm,
1035275970Scy	int32_t	    rd
1036275970Scy	)
1037275970Scy{
1038275970Scy	ntpcal_split split;
1039289764Sglebius	int	     leapy;
1040275970Scy
1041275970Scy	/* get day-of-week first */
1042358659Scy	utm->tm_wday = i32mod7(rd);
1043275970Scy
1044275970Scy	/* get year and day-of-year */
1045289764Sglebius	split = ntpcal_split_eradays(rd - 1, &leapy);
1046275970Scy	utm->tm_year = split.hi - 1899;
1047275970Scy	utm->tm_yday = split.lo;	/* 0-based */
1048275970Scy
1049275970Scy	/* convert to month and mday */
1050289764Sglebius	split = ntpcal_split_yeardays(split.lo, leapy);
1051275970Scy	utm->tm_mon  = split.hi;	/* 0-based */
1052275970Scy	utm->tm_mday = split.lo + 1;	/* 1-based */
1053275970Scy
1054289764Sglebius	return leapy;
1055275970Scy}
1056275970Scy
1057275970Scy/*
1058275970Scy *---------------------------------------------------------------------
1059275970Scy * Take a value of seconds since midnight and split it into hhmmss in a
1060275970Scy * 'struct calendar'.
1061275970Scy *---------------------------------------------------------------------
1062275970Scy */
1063275970Scyint32_t
1064275970Scyntpcal_daysec_to_date(
1065275970Scy	struct calendar *jd,
1066275970Scy	int32_t		sec
1067275970Scy	)
1068275970Scy{
1069275970Scy	int32_t days;
1070275970Scy	int   ts[3];
1071282408Scy
1072275970Scy	days = priv_timesplit(ts, sec);
1073275970Scy	jd->hour   = (uint8_t)ts[0];
1074275970Scy	jd->minute = (uint8_t)ts[1];
1075275970Scy	jd->second = (uint8_t)ts[2];
1076275970Scy
1077275970Scy	return days;
1078275970Scy}
1079275970Scy
1080275970Scy/*
1081275970Scy *---------------------------------------------------------------------
1082275970Scy * Take a value of seconds since midnight and split it into hhmmss in a
1083275970Scy * 'struct tm'.
1084275970Scy *---------------------------------------------------------------------
1085275970Scy */
1086275970Scyint32_t
1087275970Scyntpcal_daysec_to_tm(
1088275970Scy	struct tm *utm,
1089275970Scy	int32_t	   sec
1090275970Scy	)
1091275970Scy{
1092275970Scy	int32_t days;
1093275970Scy	int32_t ts[3];
1094282408Scy
1095275970Scy	days = priv_timesplit(ts, sec);
1096275970Scy	utm->tm_hour = ts[0];
1097275970Scy	utm->tm_min  = ts[1];
1098275970Scy	utm->tm_sec  = ts[2];
1099275970Scy
1100275970Scy	return days;
1101275970Scy}
1102275970Scy
1103275970Scy/*
1104275970Scy *---------------------------------------------------------------------
1105275970Scy * take a split representation for day/second-of-day and day offset
1106275970Scy * and convert it to a 'struct calendar'. The seconds will be normalised
1107275970Scy * into the range of a day, and the day will be adjusted accordingly.
1108275970Scy *
1109275970Scy * returns >0 if the result is in a leap year, 0 if in a regular
1110275970Scy * year and <0 if the result did not fit into the calendar struct.
1111275970Scy *---------------------------------------------------------------------
1112275970Scy */
1113275970Scyint
1114275970Scyntpcal_daysplit_to_date(
1115275970Scy	struct calendar	   *jd,
1116275970Scy	const ntpcal_split *ds,
1117275970Scy	int32_t		    dof
1118275970Scy	)
1119275970Scy{
1120275970Scy	dof += ntpcal_daysec_to_date(jd, ds->lo);
1121275970Scy	return ntpcal_rd_to_date(jd, ds->hi + dof);
1122275970Scy}
1123275970Scy
1124275970Scy/*
1125275970Scy *---------------------------------------------------------------------
1126275970Scy * take a split representation for day/second-of-day and day offset
1127275970Scy * and convert it to a 'struct tm'. The seconds will be normalised
1128275970Scy * into the range of a day, and the day will be adjusted accordingly.
1129275970Scy *
1130275970Scy * returns 1 if the result is in a leap year and zero if in a regular
1131275970Scy * year.
1132275970Scy *---------------------------------------------------------------------
1133275970Scy */
1134275970Scyint
1135275970Scyntpcal_daysplit_to_tm(
1136275970Scy	struct tm	   *utm,
1137275970Scy	const ntpcal_split *ds ,
1138275970Scy	int32_t		    dof
1139275970Scy	)
1140275970Scy{
1141275970Scy	dof += ntpcal_daysec_to_tm(utm, ds->lo);
1142275970Scy
1143275970Scy	return ntpcal_rd_to_tm(utm, ds->hi + dof);
1144275970Scy}
1145275970Scy
1146275970Scy/*
1147275970Scy *---------------------------------------------------------------------
1148275970Scy * Take a UN*X time and convert to a calendar structure.
1149275970Scy *---------------------------------------------------------------------
1150275970Scy */
1151275970Scyint
1152275970Scyntpcal_time_to_date(
1153275970Scy	struct calendar	*jd,
1154275970Scy	const vint64	*ts
1155275970Scy	)
1156275970Scy{
1157275970Scy	ntpcal_split ds;
1158275970Scy
1159275970Scy	ds = ntpcal_daysplit(ts);
1160275970Scy	ds.hi += ntpcal_daysec_to_date(jd, ds.lo);
1161275970Scy	ds.hi += DAY_UNIX_STARTS;
1162275970Scy
1163275970Scy	return ntpcal_rd_to_date(jd, ds.hi);
1164275970Scy}
1165275970Scy
1166275970Scy
1167275970Scy/*
1168309007Sdelphij * ====================================================================
1169275970Scy *
1170275970Scy * merging composite entities
1171275970Scy *
1172309007Sdelphij * ====================================================================
1173275970Scy */
1174275970Scy
1175358659Scy#if !defined(HAVE_INT64)
1176358659Scy/* multiplication helper. Seconds in days and weeks are multiples of 128,
1177358659Scy * and without that factor fit well into 16 bit. So a multiplication
1178358659Scy * of 32bit by 16bit and some shifting can be used on pure 32bit machines
1179358659Scy * with compilers that do not support 64bit integers.
1180358659Scy *
1181358659Scy * Calculate ( hi * mul * 128 ) + lo
1182358659Scy */
1183358659Scystatic vint64
1184358659Scy_dwjoin(
1185358659Scy	uint16_t	mul,
1186358659Scy	int32_t		hi,
1187358659Scy	int32_t		lo
1188358659Scy	)
1189358659Scy{
1190358659Scy	vint64		res;
1191358659Scy	uint32_t	p1, p2, sf;
1192358659Scy
1193358659Scy	/* get sign flag and absolute value of 'hi' in p1 */
1194358659Scy	sf = (uint32_t)-(hi < 0);
1195358659Scy	p1 = ((uint32_t)hi + sf) ^ sf;
1196358659Scy
1197358659Scy	/* assemble major units: res <- |hi| * mul */
1198358659Scy	res.D_s.lo = (p1 & 0xFFFF) * mul;
1199358659Scy	res.D_s.hi = 0;
1200358659Scy	p1 = (p1 >> 16) * mul;
1201358659Scy	p2 = p1 >> 16;
1202358659Scy	p1 = p1 << 16;
1203358659Scy	M_ADD(res.D_s.hi, res.D_s.lo, p2, p1);
1204358659Scy
1205358659Scy	/* mul by 128, using shift: res <-- res << 7 */
1206358659Scy	res.D_s.hi = (res.D_s.hi << 7) | (res.D_s.lo >> 25);
1207358659Scy	res.D_s.lo = (res.D_s.lo << 7);
1208358659Scy
1209358659Scy	/* fix up sign: res <-- (res + [sf|sf]) ^ [sf|sf] */
1210358659Scy	M_ADD(res.D_s.hi, res.D_s.lo, sf, sf);
1211358659Scy	res.D_s.lo ^= sf;
1212358659Scy	res.D_s.hi ^= sf;
1213358659Scy
1214358659Scy	/* properly add seconds: res <-- res + [sx(lo)|lo] */
1215358659Scy	p2 = (uint32_t)-(lo < 0);
1216358659Scy	p1 = (uint32_t)lo;
1217358659Scy	M_ADD(res.D_s.hi, res.D_s.lo, p2, p1);
1218358659Scy	return res;
1219358659Scy}
1220358659Scy#endif
1221358659Scy
1222275970Scy/*
1223275970Scy *---------------------------------------------------------------------
1224275970Scy * Merge a number of days and a number of seconds into seconds,
1225275970Scy * expressed in 64 bits to avoid overflow.
1226275970Scy *---------------------------------------------------------------------
1227275970Scy */
1228275970Scyvint64
1229275970Scyntpcal_dayjoin(
1230275970Scy	int32_t days,
1231275970Scy	int32_t secs
1232275970Scy	)
1233275970Scy{
1234275970Scy	vint64 res;
1235275970Scy
1236289764Sglebius#   if defined(HAVE_INT64)
1237275970Scy
1238275970Scy	res.q_s	 = days;
1239275970Scy	res.q_s *= SECSPERDAY;
1240275970Scy	res.q_s += secs;
1241275970Scy
1242289764Sglebius#   else
1243275970Scy
1244358659Scy	res = _dwjoin(675, days, secs);
1245275970Scy
1246358659Scy#   endif
1247275970Scy
1248358659Scy	return res;
1249358659Scy}
1250275970Scy
1251358659Scy/*
1252358659Scy *---------------------------------------------------------------------
1253358659Scy * Merge a number of weeks and a number of seconds into seconds,
1254358659Scy * expressed in 64 bits to avoid overflow.
1255358659Scy *---------------------------------------------------------------------
1256358659Scy */
1257358659Scyvint64
1258358659Scyntpcal_weekjoin(
1259358659Scy	int32_t week,
1260358659Scy	int32_t secs
1261358659Scy	)
1262358659Scy{
1263358659Scy	vint64 res;
1264275970Scy
1265358659Scy#   if defined(HAVE_INT64)
1266282408Scy
1267358659Scy	res.q_s	 = week;
1268358659Scy	res.q_s *= SECSPERWEEK;
1269358659Scy	res.q_s += secs;
1270275970Scy
1271358659Scy#   else
1272358659Scy
1273358659Scy	res = _dwjoin(4725, week, secs);
1274358659Scy
1275289764Sglebius#   endif
1276275970Scy
1277275970Scy	return res;
1278275970Scy}
1279275970Scy
1280275970Scy/*
1281275970Scy *---------------------------------------------------------------------
1282289764Sglebius * get leap years since epoch in elapsed years
1283275970Scy *---------------------------------------------------------------------
1284275970Scy */
1285275970Scyint32_t
1286289764Sglebiusntpcal_leapyears_in_years(
1287275970Scy	int32_t years
1288275970Scy	)
1289275970Scy{
1290289764Sglebius	/* We use the in-out-in algorithm here, using the one's
1291289764Sglebius	 * complement division trick for negative numbers. The chained
1292289764Sglebius	 * division sequence by 4/25/4 gives the compiler the chance to
1293289764Sglebius	 * get away with only one true division and doing shifts otherwise.
1294289764Sglebius	 */
1295275970Scy
1296358659Scy	uint32_t sf32, sum, uyear;
1297275970Scy
1298358659Scy	sf32  = int32_sflag(years);
1299358659Scy	uyear = (uint32_t)years;
1300358659Scy	uyear ^= sf32;
1301289764Sglebius
1302289764Sglebius	sum  = (uyear /=  4u);	/*   4yr rule --> IN  */
1303289764Sglebius	sum -= (uyear /= 25u);	/* 100yr rule --> OUT */
1304289764Sglebius	sum += (uyear /=  4u);	/* 400yr rule --> IN  */
1305289764Sglebius
1306289764Sglebius	/* Thanks to the alternation of IN/OUT/IN we can do the sum
1307289764Sglebius	 * directly and have a single one's complement operation
1308289764Sglebius	 * here. (Only if the years are negative, of course.) Otherwise
1309289764Sglebius	 * the one's complement would have to be done when
1310289764Sglebius	 * adding/subtracting the terms.
1311275970Scy	 */
1312358659Scy	return uint32_2cpl_to_int32(sf32 ^ sum);
1313275970Scy}
1314275970Scy
1315275970Scy/*
1316275970Scy *---------------------------------------------------------------------
1317289764Sglebius * Convert elapsed years in Era into elapsed days in Era.
1318289764Sglebius *---------------------------------------------------------------------
1319289764Sglebius */
1320289764Sglebiusint32_t
1321289764Sglebiusntpcal_days_in_years(
1322289764Sglebius	int32_t years
1323289764Sglebius	)
1324289764Sglebius{
1325289764Sglebius	return years * DAYSPERYEAR + ntpcal_leapyears_in_years(years);
1326289764Sglebius}
1327289764Sglebius
1328289764Sglebius/*
1329289764Sglebius *---------------------------------------------------------------------
1330275970Scy * Convert a number of elapsed month in a year into elapsed days in year.
1331275970Scy *
1332275970Scy * The month will be normalized, and 'res.hi' will contain the
1333275970Scy * excessive years that must be considered when converting the years,
1334275970Scy * while 'res.lo' will contain the number of elapsed days since start
1335275970Scy * of the year.
1336275970Scy *
1337275970Scy * This code uses the shifted-month-approach to convert month to days,
1338275970Scy * because then there is no need to have explicit leap year
1339275970Scy * information.	 The slight disadvantage is that for most month values
1340275970Scy * the result is a negative value, and the year excess is one; the
1341275970Scy * conversion is then simply based on the start of the following year.
1342275970Scy *---------------------------------------------------------------------
1343275970Scy */
1344275970Scyntpcal_split
1345275970Scyntpcal_days_in_months(
1346275970Scy	int32_t m
1347275970Scy	)
1348275970Scy{
1349275970Scy	ntpcal_split res;
1350275970Scy
1351358659Scy	/* Add ten months with proper year adjustment. */
1352358659Scy	if (m < 2) {
1353358659Scy	    res.lo  = m + 10;
1354358659Scy	    res.hi  = 0;
1355358659Scy	} else {
1356358659Scy	    res.lo  = m - 2;
1357358659Scy	    res.hi  = 1;
1358358659Scy	}
1359289764Sglebius
1360358659Scy	/* Possibly normalise by floor division. This does not hapen for
1361358659Scy	 * input in normal range. */
1362275970Scy	if (res.lo < 0 || res.lo >= 12) {
1363358659Scy		uint32_t mu, Q, sf32;
1364358659Scy		sf32 = int32_sflag(res.lo);
1365358659Scy		mu   = (uint32_t)res.lo;
1366358659Scy		Q    = sf32 ^ ((sf32 ^ mu) / 12u);
1367358659Scy
1368289764Sglebius		res.hi += uint32_2cpl_to_int32(Q);
1369358659Scy		res.lo	= mu - Q * 12u;
1370275970Scy	}
1371275970Scy
1372358659Scy	/* Get cummulated days in year with unshift. Use the fractional
1373358659Scy	 * interpolation with smallest possible power of two in the
1374358659Scy	 * divider.
1375358659Scy	 */
1376358659Scy	res.lo = ((res.lo * 979 + 16) >> 5) - 306;
1377358659Scy
1378275970Scy	return res;
1379275970Scy}
1380275970Scy
1381275970Scy/*
1382275970Scy *---------------------------------------------------------------------
1383275970Scy * Convert ELAPSED years/months/days of gregorian calendar to elapsed
1384275970Scy * days in Gregorian epoch.
1385275970Scy *
1386275970Scy * If you want to convert years and days-of-year, just give a month of
1387275970Scy * zero.
1388275970Scy *---------------------------------------------------------------------
1389275970Scy */
1390275970Scyint32_t
1391275970Scyntpcal_edate_to_eradays(
1392275970Scy	int32_t years,
1393275970Scy	int32_t mons,
1394275970Scy	int32_t mdays
1395275970Scy	)
1396275970Scy{
1397275970Scy	ntpcal_split tmp;
1398275970Scy	int32_t	     res;
1399275970Scy
1400275970Scy	if (mons) {
1401275970Scy		tmp = ntpcal_days_in_months(mons);
1402275970Scy		res = ntpcal_days_in_years(years + tmp.hi) + tmp.lo;
1403275970Scy	} else
1404275970Scy		res = ntpcal_days_in_years(years);
1405275970Scy	res += mdays;
1406275970Scy
1407275970Scy	return res;
1408275970Scy}
1409275970Scy
1410275970Scy/*
1411275970Scy *---------------------------------------------------------------------
1412275970Scy * Convert ELAPSED years/months/days of gregorian calendar to elapsed
1413275970Scy * days in year.
1414275970Scy *
1415309007Sdelphij * Note: This will give the true difference to the start of the given
1416309007Sdelphij * year, even if months & days are off-scale.
1417275970Scy *---------------------------------------------------------------------
1418275970Scy */
1419275970Scyint32_t
1420275970Scyntpcal_edate_to_yeardays(
1421275970Scy	int32_t years,
1422275970Scy	int32_t mons,
1423275970Scy	int32_t mdays
1424275970Scy	)
1425275970Scy{
1426275970Scy	ntpcal_split tmp;
1427275970Scy
1428275970Scy	if (0 <= mons && mons < 12) {
1429358659Scy		if (mons >= 2)
1430358659Scy			mdays -= 2 - is_leapyear(years+1);
1431358659Scy		mdays += (489 * mons + 8) >> 4;
1432275970Scy	} else {
1433275970Scy		tmp = ntpcal_days_in_months(mons);
1434275970Scy		mdays += tmp.lo
1435275970Scy		       + ntpcal_days_in_years(years + tmp.hi)
1436275970Scy		       - ntpcal_days_in_years(years);
1437275970Scy	}
1438275970Scy
1439275970Scy	return mdays;
1440275970Scy}
1441275970Scy
1442275970Scy/*
1443275970Scy *---------------------------------------------------------------------
1444275970Scy * Convert elapsed days and the hour/minute/second information into
1445275970Scy * total seconds.
1446275970Scy *
1447275970Scy * If 'isvalid' is not NULL, do a range check on the time specification
1448275970Scy * and tell if the time input is in the normal range, permitting for a
1449275970Scy * single leapsecond.
1450275970Scy *---------------------------------------------------------------------
1451275970Scy */
1452275970Scyint32_t
1453275970Scyntpcal_etime_to_seconds(
1454275970Scy	int32_t hours,
1455275970Scy	int32_t minutes,
1456275970Scy	int32_t seconds
1457275970Scy	)
1458275970Scy{
1459275970Scy	int32_t res;
1460275970Scy
1461275970Scy	res = (hours * MINSPERHR + minutes) * SECSPERMIN + seconds;
1462275970Scy
1463275970Scy	return res;
1464275970Scy}
1465275970Scy
1466275970Scy/*
1467275970Scy *---------------------------------------------------------------------
1468275970Scy * Convert the date part of a 'struct tm' (that is, year, month,
1469275970Scy * day-of-month) into the RD of that day.
1470275970Scy *---------------------------------------------------------------------
1471275970Scy */
1472275970Scyint32_t
1473275970Scyntpcal_tm_to_rd(
1474275970Scy	const struct tm *utm
1475275970Scy	)
1476275970Scy{
1477275970Scy	return ntpcal_edate_to_eradays(utm->tm_year + 1899,
1478275970Scy				       utm->tm_mon,
1479275970Scy				       utm->tm_mday - 1) + 1;
1480275970Scy}
1481275970Scy
1482275970Scy/*
1483275970Scy *---------------------------------------------------------------------
1484275970Scy * Convert the date part of a 'struct calendar' (that is, year, month,
1485275970Scy * day-of-month) into the RD of that day.
1486275970Scy *---------------------------------------------------------------------
1487275970Scy */
1488275970Scyint32_t
1489275970Scyntpcal_date_to_rd(
1490275970Scy	const struct calendar *jd
1491275970Scy	)
1492275970Scy{
1493275970Scy	return ntpcal_edate_to_eradays((int32_t)jd->year - 1,
1494275970Scy				       (int32_t)jd->month - 1,
1495275970Scy				       (int32_t)jd->monthday - 1) + 1;
1496275970Scy}
1497275970Scy
1498275970Scy/*
1499275970Scy *---------------------------------------------------------------------
1500275970Scy * convert a year number to rata die of year start
1501275970Scy *---------------------------------------------------------------------
1502275970Scy */
1503275970Scyint32_t
1504275970Scyntpcal_year_to_ystart(
1505275970Scy	int32_t year
1506275970Scy	)
1507275970Scy{
1508275970Scy	return ntpcal_days_in_years(year - 1) + 1;
1509275970Scy}
1510275970Scy
1511275970Scy/*
1512275970Scy *---------------------------------------------------------------------
1513275970Scy * For a given RD, get the RD of the associated year start,
1514275970Scy * that is, the RD of the last January,1st on or before that day.
1515275970Scy *---------------------------------------------------------------------
1516275970Scy */
1517275970Scyint32_t
1518275970Scyntpcal_rd_to_ystart(
1519275970Scy	int32_t rd
1520275970Scy	)
1521275970Scy{
1522275970Scy	/*
1523275970Scy	 * Rather simple exercise: split the day number into elapsed
1524275970Scy	 * years and elapsed days, then remove the elapsed days from the
1525275970Scy	 * input value. Nice'n sweet...
1526275970Scy	 */
1527275970Scy	return rd - ntpcal_split_eradays(rd - 1, NULL).lo;
1528275970Scy}
1529275970Scy
1530275970Scy/*
1531275970Scy *---------------------------------------------------------------------
1532275970Scy * For a given RD, get the RD of the associated month start.
1533275970Scy *---------------------------------------------------------------------
1534275970Scy */
1535275970Scyint32_t
1536275970Scyntpcal_rd_to_mstart(
1537275970Scy	int32_t rd
1538275970Scy	)
1539275970Scy{
1540275970Scy	ntpcal_split split;
1541275970Scy	int	     leaps;
1542275970Scy
1543275970Scy	split = ntpcal_split_eradays(rd - 1, &leaps);
1544275970Scy	split = ntpcal_split_yeardays(split.lo, leaps);
1545275970Scy
1546275970Scy	return rd - split.lo;
1547275970Scy}
1548275970Scy
1549275970Scy/*
1550275970Scy *---------------------------------------------------------------------
1551275970Scy * take a 'struct calendar' and get the seconds-of-day from it.
1552275970Scy *---------------------------------------------------------------------
1553275970Scy */
1554275970Scyint32_t
1555275970Scyntpcal_date_to_daysec(
1556275970Scy	const struct calendar *jd
1557275970Scy	)
1558275970Scy{
1559275970Scy	return ntpcal_etime_to_seconds(jd->hour, jd->minute,
1560275970Scy				       jd->second);
1561275970Scy}
1562275970Scy
1563275970Scy/*
1564275970Scy *---------------------------------------------------------------------
1565275970Scy * take a 'struct tm' and get the seconds-of-day from it.
1566275970Scy *---------------------------------------------------------------------
1567275970Scy */
1568275970Scyint32_t
1569275970Scyntpcal_tm_to_daysec(
1570275970Scy	const struct tm *utm
1571275970Scy	)
1572275970Scy{
1573275970Scy	return ntpcal_etime_to_seconds(utm->tm_hour, utm->tm_min,
1574275970Scy				       utm->tm_sec);
1575275970Scy}
1576275970Scy
1577275970Scy/*
1578275970Scy *---------------------------------------------------------------------
1579275970Scy * take a 'struct calendar' and convert it to a 'time_t'
1580275970Scy *---------------------------------------------------------------------
1581275970Scy */
1582275970Scytime_t
1583275970Scyntpcal_date_to_time(
1584275970Scy	const struct calendar *jd
1585275970Scy	)
1586275970Scy{
1587358659Scy	vint64	join;
1588275970Scy	int32_t days, secs;
1589275970Scy
1590275970Scy	days = ntpcal_date_to_rd(jd) - DAY_UNIX_STARTS;
1591275970Scy	secs = ntpcal_date_to_daysec(jd);
1592275970Scy	join = ntpcal_dayjoin(days, secs);
1593275970Scy
1594275970Scy	return vint64_to_time(&join);
1595275970Scy}
1596275970Scy
1597275970Scy
1598275970Scy/*
1599309007Sdelphij * ====================================================================
1600275970Scy *
1601275970Scy * extended and unchecked variants of caljulian/caltontp
1602275970Scy *
1603309007Sdelphij * ====================================================================
1604275970Scy */
1605275970Scyint
1606275970Scyntpcal_ntp64_to_date(
1607275970Scy	struct calendar *jd,
1608358659Scy	const vint64	*ntp
1609275970Scy	)
1610275970Scy{
1611275970Scy	ntpcal_split ds;
1612282408Scy
1613275970Scy	ds = ntpcal_daysplit(ntp);
1614275970Scy	ds.hi += ntpcal_daysec_to_date(jd, ds.lo);
1615275970Scy
1616275970Scy	return ntpcal_rd_to_date(jd, ds.hi + DAY_NTP_STARTS);
1617275970Scy}
1618275970Scy
1619275970Scyint
1620275970Scyntpcal_ntp_to_date(
1621275970Scy	struct calendar *jd,
1622275970Scy	uint32_t	 ntp,
1623275970Scy	const time_t	*piv
1624275970Scy	)
1625275970Scy{
1626275970Scy	vint64	ntp64;
1627282408Scy
1628275970Scy	/*
1629275970Scy	 * Unfold ntp time around current time into NTP domain. Split
1630275970Scy	 * into days and seconds, shift days into CE domain and
1631275970Scy	 * process the parts.
1632275970Scy	 */
1633275970Scy	ntp64 = ntpcal_ntp_to_ntp(ntp, piv);
1634275970Scy	return ntpcal_ntp64_to_date(jd, &ntp64);
1635275970Scy}
1636275970Scy
1637275970Scy
1638275970Scyvint64
1639275970Scyntpcal_date_to_ntp64(
1640275970Scy	const struct calendar *jd
1641275970Scy	)
1642275970Scy{
1643275970Scy	/*
1644275970Scy	 * Convert date to NTP. Ignore yearday, use d/m/y only.
1645275970Scy	 */
1646275970Scy	return ntpcal_dayjoin(ntpcal_date_to_rd(jd) - DAY_NTP_STARTS,
1647275970Scy			      ntpcal_date_to_daysec(jd));
1648275970Scy}
1649275970Scy
1650275970Scy
1651275970Scyuint32_t
1652275970Scyntpcal_date_to_ntp(
1653275970Scy	const struct calendar *jd
1654275970Scy	)
1655275970Scy{
1656275970Scy	/*
1657358659Scy	 * Get lower half of 64bit NTP timestamp from date/time.
1658275970Scy	 */
1659275970Scy	return ntpcal_date_to_ntp64(jd).d_s.lo;
1660275970Scy}
1661275970Scy
1662275970Scy
1663275970Scy
1664275970Scy/*
1665309007Sdelphij * ====================================================================
1666275970Scy *
1667275970Scy * day-of-week calculations
1668275970Scy *
1669309007Sdelphij * ====================================================================
1670275970Scy */
1671275970Scy/*
1672275970Scy * Given a RataDie and a day-of-week, calculate a RDN that is reater-than,
1673275970Scy * greater-or equal, closest, less-or-equal or less-than the given RDN
1674275970Scy * and denotes the given day-of-week
1675275970Scy */
1676275970Scyint32_t
1677275970Scyntpcal_weekday_gt(
1678275970Scy	int32_t rdn,
1679275970Scy	int32_t dow
1680275970Scy	)
1681275970Scy{
1682275970Scy	return ntpcal_periodic_extend(rdn+1, dow, 7);
1683275970Scy}
1684275970Scy
1685275970Scyint32_t
1686275970Scyntpcal_weekday_ge(
1687275970Scy	int32_t rdn,
1688275970Scy	int32_t dow
1689275970Scy	)
1690275970Scy{
1691275970Scy	return ntpcal_periodic_extend(rdn, dow, 7);
1692275970Scy}
1693275970Scy
1694275970Scyint32_t
1695275970Scyntpcal_weekday_close(
1696275970Scy	int32_t rdn,
1697275970Scy	int32_t dow
1698275970Scy	)
1699275970Scy{
1700275970Scy	return ntpcal_periodic_extend(rdn-3, dow, 7);
1701275970Scy}
1702275970Scy
1703275970Scyint32_t
1704275970Scyntpcal_weekday_le(
1705275970Scy	int32_t rdn,
1706275970Scy	int32_t dow
1707275970Scy	)
1708275970Scy{
1709275970Scy	return ntpcal_periodic_extend(rdn, dow, -7);
1710275970Scy}
1711275970Scy
1712275970Scyint32_t
1713275970Scyntpcal_weekday_lt(
1714275970Scy	int32_t rdn,
1715275970Scy	int32_t dow
1716275970Scy	)
1717275970Scy{
1718275970Scy	return ntpcal_periodic_extend(rdn-1, dow, -7);
1719275970Scy}
1720275970Scy
1721275970Scy/*
1722309007Sdelphij * ====================================================================
1723275970Scy *
1724275970Scy * ISO week-calendar conversions
1725275970Scy *
1726275970Scy * The ISO8601 calendar defines a calendar of years, weeks and weekdays.
1727275970Scy * It is related to the Gregorian calendar, and a ISO year starts at the
1728275970Scy * Monday closest to Jan,1st of the corresponding Gregorian year.  A ISO
1729275970Scy * calendar year has always 52 or 53 weeks, and like the Grogrian
1730275970Scy * calendar the ISO8601 calendar repeats itself every 400 years, or
1731275970Scy * 146097 days, or 20871 weeks.
1732275970Scy *
1733275970Scy * While it is possible to write ISO calendar functions based on the
1734275970Scy * Gregorian calendar functions, the following implementation takes a
1735275970Scy * different approach, based directly on years and weeks.
1736275970Scy *
1737275970Scy * Analysis of the tabulated data shows that it is not possible to
1738275970Scy * interpolate from years to weeks over a full 400 year range; cyclic
1739275970Scy * shifts over 400 years do not provide a solution here. But it *is*
1740275970Scy * possible to interpolate over every single century of the 400-year
1741275970Scy * cycle. (The centennial leap year rule seems to be the culprit here.)
1742275970Scy *
1743275970Scy * It can be shown that a conversion from years to weeks can be done
1744275970Scy * using a linear transformation of the form
1745275970Scy *
1746275970Scy *   w = floor( y * a + b )
1747275970Scy *
1748275970Scy * where the slope a must hold to
1749275970Scy *
1750275970Scy *  52.1780821918 <= a < 52.1791044776
1751275970Scy *
1752275970Scy * and b must be chosen according to the selected slope and the number
1753275970Scy * of the century in a 400-year period.
1754275970Scy *
1755275970Scy * The inverse calculation can also be done in this way. Careful scaling
1756275970Scy * provides an unlimited set of integer coefficients a,k,b that enable
1757275970Scy * us to write the calulation in the form
1758275970Scy *
1759275970Scy *   w = (y * a	 + b ) / k
1760275970Scy *   y = (w * a' + b') / k'
1761275970Scy *
1762358659Scy * In this implementation the values of k and k' are chosen to be the
1763275970Scy * smallest possible powers of two, so the division can be implemented
1764275970Scy * as shifts if the optimiser chooses to do so.
1765275970Scy *
1766309007Sdelphij * ====================================================================
1767275970Scy */
1768275970Scy
1769275970Scy/*
1770275970Scy * Given a number of elapsed (ISO-)years since the begin of the
1771275970Scy * christian era, return the number of elapsed weeks corresponding to
1772275970Scy * the number of years.
1773275970Scy */
1774275970Scyint32_t
1775275970Scyisocal_weeks_in_years(
1776275970Scy	int32_t years
1777275970Scy	)
1778358659Scy{
1779275970Scy	/*
1780275970Scy	 * use: w = (y * 53431 + b[c]) / 1024 as interpolation
1781275970Scy	 */
1782289764Sglebius	static const uint16_t bctab[4] = { 157, 449, 597, 889 };
1783275970Scy
1784358659Scy	int32_t	 cs, cw;
1785358659Scy	uint32_t cc, ci, yu, sf32;
1786275970Scy
1787358659Scy	sf32 = int32_sflag(years);
1788358659Scy	yu   = (uint32_t)years;
1789358659Scy
1790289764Sglebius	/* split off centuries, using floor division */
1791358659Scy	cc  = sf32 ^ ((sf32 ^ yu) / 100u);
1792289764Sglebius	yu -= cc * 100u;
1793275970Scy
1794289764Sglebius	/* calculate century cycles shift and cycle index:
1795289764Sglebius	 * Assuming a century is 5217 weeks, we have to add a cycle
1796289764Sglebius	 * shift that is 3 for every 4 centuries, because 3 of the four
1797289764Sglebius	 * centuries have 5218 weeks. So '(cc*3 + 1) / 4' is the actual
1798289764Sglebius	 * correction, and the second century is the defective one.
1799289764Sglebius	 *
1800289764Sglebius	 * Needs floor division by 4, which is done with masking and
1801289764Sglebius	 * shifting.
1802275970Scy	 */
1803289764Sglebius	ci = cc * 3u + 1;
1804358659Scy	cs = uint32_2cpl_to_int32(sf32 ^ ((sf32 ^ ci) >> 2));
1805358659Scy	ci = ci & 3u;
1806358659Scy
1807289764Sglebius	/* Get weeks in century. Can use plain division here as all ops
1808289764Sglebius	 * are >= 0,  and let the compiler sort out the possible
1809289764Sglebius	 * optimisations.
1810289764Sglebius	 */
1811289764Sglebius	cw = (yu * 53431u + bctab[ci]) / 1024u;
1812275970Scy
1813289764Sglebius	return uint32_2cpl_to_int32(cc) * 5217 + cs + cw;
1814275970Scy}
1815275970Scy
1816275970Scy/*
1817275970Scy * Given a number of elapsed weeks since the begin of the christian
1818275970Scy * era, split this number into the number of elapsed years in res.hi
1819275970Scy * and the excessive number of weeks in res.lo. (That is, res.lo is
1820275970Scy * the number of elapsed weeks in the remaining partial year.)
1821275970Scy */
1822275970Scyntpcal_split
1823275970Scyisocal_split_eraweeks(
1824275970Scy	int32_t weeks
1825275970Scy	)
1826275970Scy{
1827275970Scy	/*
1828275970Scy	 * use: y = (w * 157 + b[c]) / 8192 as interpolation
1829275970Scy	 */
1830289764Sglebius
1831289764Sglebius	static const uint16_t bctab[4] = { 85, 130, 17, 62 };
1832289764Sglebius
1833275970Scy	ntpcal_split res;
1834358659Scy	int32_t	 cc, ci;
1835358659Scy	uint32_t sw, cy, Q;
1836275970Scy
1837358659Scy	/* Use two fast cycle-split divisions again. Herew e want to
1838358659Scy	 * execute '(weeks * 4 + 2) /% 20871' under floor division rules
1839358659Scy	 * in the first step.
1840289764Sglebius	 *
1841358659Scy	 * This is of course (again) susceptible to internal overflow if
1842358659Scy	 * coded directly in 32bit. And again we use 64bit division on
1843358659Scy	 * a 64bit target and exact division after calculating the
1844358659Scy	 * remainder first on a 32bit target. With the smaller divider,
1845358659Scy	 * that's even a bit neater.
1846275970Scy	 */
1847358659Scy#   if defined(HAVE_64BITREGS)
1848358659Scy
1849358659Scy	/* Full floor division with 64bit values. */
1850358659Scy	uint64_t sf64, sw64;
1851358659Scy	sf64 = (uint64_t)-(weeks < 0);
1852358659Scy	sw64 = ((uint64_t)weeks << 2) | 2u;
1853358659Scy	Q    = (uint32_t)(sf64 ^ ((sf64 ^ sw64) / GREGORIAN_CYCLE_WEEKS));
1854358659Scy	sw   = (uint32_t)(sw64 - Q * GREGORIAN_CYCLE_WEEKS);
1855358659Scy
1856358659Scy#   else
1857358659Scy
1858358659Scy	/* Exact division after calculating the remainder via partial
1859358659Scy	 * reduction by digit sum.
1860358659Scy	 * (-2^33) % 20871     --> 5491	     : the sign bit value
1861358659Scy	 * ( 2^20) % 20871     --> 5026	     : the upper digit value
1862358659Scy	 * modinv(20871, 2^32) --> 330081335 : the inverse
1863358659Scy	 */
1864358659Scy	uint32_t ux = ((uint32_t)weeks << 2) | 2;
1865358659Scy	sw  = (weeks < 0) ? 5491u : 0u;		  /* sign dgt */
1866358659Scy	sw += ((weeks >> 18) & 0x01FFFu) * 5026u; /* hi dgt (src!) */
1867358659Scy	sw += (ux & 0xFFFFFu);			  /* lo dgt */
1868358659Scy	sw %= GREGORIAN_CYCLE_WEEKS;		  /* full reduction */
1869358659Scy	Q   = (ux  - sw) * 330081335u;		  /* exact div */
1870358659Scy
1871358659Scy#   endif
1872358659Scy
1873358659Scy	ci  = Q & 3u;
1874289764Sglebius	cc  = uint32_2cpl_to_int32(Q);
1875275970Scy
1876289764Sglebius	/* Split off years; sw >= 0 here! The scaled weeks in the years
1877289764Sglebius	 * are scaled up by 157 afterwards.
1878358659Scy	 */
1879289764Sglebius	sw  = (sw / 4u) * 157u + bctab[ci];
1880358659Scy	cy  = sw / 8192u;	/* sw >> 13 , let the compiler sort it out */
1881358659Scy	sw  = sw % 8192u;	/* sw & 8191, let the compiler sort it out */
1882289764Sglebius
1883289764Sglebius	/* assemble elapsed years and downscale the elapsed weeks in
1884289764Sglebius	 * the year.
1885275970Scy	 */
1886289764Sglebius	res.hi = 100*cc + cy;
1887289764Sglebius	res.lo = sw / 157u;
1888282408Scy
1889275970Scy	return res;
1890275970Scy}
1891275970Scy
1892275970Scy/*
1893275970Scy * Given a second in the NTP time scale and a pivot, expand the NTP
1894275970Scy * time stamp around the pivot and convert into an ISO calendar time
1895275970Scy * stamp.
1896275970Scy */
1897275970Scyint
1898275970Scyisocal_ntp64_to_date(
1899275970Scy	struct isodate *id,
1900275970Scy	const vint64   *ntp
1901275970Scy	)
1902275970Scy{
1903275970Scy	ntpcal_split ds;
1904358659Scy	int32_t	     ts[3];
1905358659Scy	uint32_t     uw, ud, sf32;
1906282408Scy
1907275970Scy	/*
1908275970Scy	 * Split NTP time into days and seconds, shift days into CE
1909275970Scy	 * domain and process the parts.
1910275970Scy	 */
1911275970Scy	ds = ntpcal_daysplit(ntp);
1912275970Scy
1913275970Scy	/* split time part */
1914275970Scy	ds.hi += priv_timesplit(ts, ds.lo);
1915275970Scy	id->hour   = (uint8_t)ts[0];
1916275970Scy	id->minute = (uint8_t)ts[1];
1917275970Scy	id->second = (uint8_t)ts[2];
1918275970Scy
1919289764Sglebius	/* split days into days and weeks, using floor division in unsigned */
1920289764Sglebius	ds.hi += DAY_NTP_STARTS - 1; /* shift from NTP to RDN */
1921358659Scy	sf32 = int32_sflag(ds.hi);
1922358659Scy	ud   = (uint32_t)ds.hi;
1923358659Scy	uw   = sf32 ^ ((sf32 ^ ud) / DAYSPERWEEK);
1924358659Scy	ud  -= uw * DAYSPERWEEK;
1925358659Scy
1926289764Sglebius	ds.hi = uint32_2cpl_to_int32(uw);
1927289764Sglebius	ds.lo = ud;
1928289764Sglebius
1929275970Scy	id->weekday = (uint8_t)ds.lo + 1;	/* weekday result    */
1930275970Scy
1931289764Sglebius	/* get year and week in year */
1932275970Scy	ds = isocal_split_eraweeks(ds.hi);	/* elapsed years&week*/
1933275970Scy	id->year = (uint16_t)ds.hi + 1;		/* shift to current  */
1934275970Scy	id->week = (uint8_t )ds.lo + 1;
1935275970Scy
1936280849Scy	return (ds.hi >= 0 && ds.hi < 0x0000FFFF);
1937275970Scy}
1938275970Scy
1939275970Scyint
1940275970Scyisocal_ntp_to_date(
1941275970Scy	struct isodate *id,
1942275970Scy	uint32_t	ntp,
1943275970Scy	const time_t   *piv
1944275970Scy	)
1945275970Scy{
1946275970Scy	vint64	ntp64;
1947282408Scy
1948275970Scy	/*
1949275970Scy	 * Unfold ntp time around current time into NTP domain, then
1950275970Scy	 * convert the full time stamp.
1951275970Scy	 */
1952275970Scy	ntp64 = ntpcal_ntp_to_ntp(ntp, piv);
1953275970Scy	return isocal_ntp64_to_date(id, &ntp64);
1954275970Scy}
1955275970Scy
1956275970Scy/*
1957275970Scy * Convert a ISO date spec into a second in the NTP time scale,
1958275970Scy * properly truncated to 32 bit.
1959275970Scy */
1960275970Scyvint64
1961275970Scyisocal_date_to_ntp64(
1962275970Scy	const struct isodate *id
1963275970Scy	)
1964275970Scy{
1965275970Scy	int32_t weeks, days, secs;
1966275970Scy
1967275970Scy	weeks = isocal_weeks_in_years((int32_t)id->year - 1)
1968275970Scy	      + (int32_t)id->week - 1;
1969275970Scy	days = weeks * 7 + (int32_t)id->weekday;
1970275970Scy	/* days is RDN of ISO date now */
1971275970Scy	secs = ntpcal_etime_to_seconds(id->hour, id->minute, id->second);
1972275970Scy
1973275970Scy	return ntpcal_dayjoin(days - DAY_NTP_STARTS, secs);
1974275970Scy}
1975275970Scy
1976275970Scyuint32_t
1977275970Scyisocal_date_to_ntp(
1978275970Scy	const struct isodate *id
1979275970Scy	)
1980275970Scy{
1981275970Scy	/*
1982358659Scy	 * Get lower half of 64bit NTP timestamp from date/time.
1983275970Scy	 */
1984275970Scy	return isocal_date_to_ntp64(id).d_s.lo;
1985275970Scy}
1986275970Scy
1987330106Sdelphij/*
1988330106Sdelphij * ====================================================================
1989330106Sdelphij * 'basedate' support functions
1990330106Sdelphij * ====================================================================
1991330106Sdelphij */
1992330106Sdelphij
1993330106Sdelphijstatic int32_t s_baseday = NTP_TO_UNIX_DAYS;
1994344884Scystatic int32_t s_gpsweek = 0;
1995330106Sdelphij
1996330106Sdelphijint32_t
1997330106Sdelphijbasedate_eval_buildstamp(void)
1998330106Sdelphij{
1999330106Sdelphij	struct calendar jd;
2000330106Sdelphij	int32_t		ed;
2001358659Scy
2002330106Sdelphij	if (!ntpcal_get_build_date(&jd))
2003330106Sdelphij		return NTP_TO_UNIX_DAYS;
2004330106Sdelphij
2005330106Sdelphij	/* The time zone of the build stamp is unspecified; we remove
2006330106Sdelphij	 * one day to provide a certain slack. And in case somebody
2007330106Sdelphij	 * fiddled with the system clock, we make sure we do not go
2008330106Sdelphij	 * before the UNIX epoch (1970-01-01). It's probably not possible
2009330106Sdelphij	 * to do this to the clock on most systems, but there are other
2010330106Sdelphij	 * ways to tweak the build stamp.
2011330106Sdelphij	 */
2012330106Sdelphij	jd.monthday -= 1;
2013330106Sdelphij	ed = ntpcal_date_to_rd(&jd) - DAY_NTP_STARTS;
2014330106Sdelphij	return (ed < NTP_TO_UNIX_DAYS) ? NTP_TO_UNIX_DAYS : ed;
2015330106Sdelphij}
2016330106Sdelphij
2017330106Sdelphijint32_t
2018330106Sdelphijbasedate_eval_string(
2019330106Sdelphij	const char * str
2020330106Sdelphij	)
2021330106Sdelphij{
2022330106Sdelphij	u_short	y,m,d;
2023330106Sdelphij	u_long	ned;
2024330106Sdelphij	int	rc, nc;
2025330106Sdelphij	size_t	sl;
2026330106Sdelphij
2027358659Scy	sl = strlen(str);
2028330106Sdelphij	rc = sscanf(str, "%4hu-%2hu-%2hu%n", &y, &m, &d, &nc);
2029330106Sdelphij	if (rc == 3 && (size_t)nc == sl) {
2030330106Sdelphij		if (m >= 1 && m <= 12 && d >= 1 && d <= 31)
2031330106Sdelphij			return ntpcal_edate_to_eradays(y-1, m-1, d)
2032330106Sdelphij			    - DAY_NTP_STARTS;
2033330106Sdelphij		goto buildstamp;
2034330106Sdelphij	}
2035330106Sdelphij
2036338530Sdelphij	rc = sscanf(str, "%lu%n", &ned, &nc);
2037330106Sdelphij	if (rc == 1 && (size_t)nc == sl) {
2038330106Sdelphij		if (ned <= INT32_MAX)
2039330106Sdelphij			return (int32_t)ned;
2040330106Sdelphij		goto buildstamp;
2041330106Sdelphij	}
2042330106Sdelphij
2043330106Sdelphij  buildstamp:
2044330106Sdelphij	msyslog(LOG_WARNING,
2045330106Sdelphij		"basedate string \"%s\" invalid, build date substituted!",
2046330106Sdelphij		str);
2047330106Sdelphij	return basedate_eval_buildstamp();
2048330106Sdelphij}
2049330106Sdelphij
2050330106Sdelphijuint32_t
2051330106Sdelphijbasedate_get_day(void)
2052330106Sdelphij{
2053330106Sdelphij	return s_baseday;
2054330106Sdelphij}
2055330106Sdelphij
2056330106Sdelphijint32_t
2057330106Sdelphijbasedate_set_day(
2058330106Sdelphij	int32_t day
2059330106Sdelphij	)
2060330106Sdelphij{
2061330106Sdelphij	struct calendar	jd;
2062330106Sdelphij	int32_t		retv;
2063330106Sdelphij
2064344884Scy	/* set NTP base date for NTP era unfolding */
2065330106Sdelphij	if (day < NTP_TO_UNIX_DAYS) {
2066330106Sdelphij		msyslog(LOG_WARNING,
2067330106Sdelphij			"baseday_set_day: invalid day (%lu), UNIX epoch substituted",
2068330106Sdelphij			(unsigned long)day);
2069330106Sdelphij		day = NTP_TO_UNIX_DAYS;
2070330106Sdelphij	}
2071358659Scy	retv = s_baseday;
2072330106Sdelphij	s_baseday = day;
2073330106Sdelphij	ntpcal_rd_to_date(&jd, day + DAY_NTP_STARTS);
2074330106Sdelphij	msyslog(LOG_INFO, "basedate set to %04hu-%02hu-%02hu",
2075330106Sdelphij		jd.year, (u_short)jd.month, (u_short)jd.monthday);
2076344884Scy
2077344884Scy	/* set GPS base week for GPS week unfolding */
2078344884Scy	day = ntpcal_weekday_ge(day + DAY_NTP_STARTS, CAL_SUNDAY)
2079344884Scy	    - DAY_NTP_STARTS;
2080344884Scy	if (day < NTP_TO_GPS_DAYS)
2081344884Scy	    day = NTP_TO_GPS_DAYS;
2082344884Scy	s_gpsweek = (day - NTP_TO_GPS_DAYS) / DAYSPERWEEK;
2083344884Scy	ntpcal_rd_to_date(&jd, day + DAY_NTP_STARTS);
2084344884Scy	msyslog(LOG_INFO, "gps base set to %04hu-%02hu-%02hu (week %d)",
2085344884Scy		jd.year, (u_short)jd.month, (u_short)jd.monthday, s_gpsweek);
2086358659Scy
2087330106Sdelphij	return retv;
2088330106Sdelphij}
2089330106Sdelphij
2090330106Sdelphijtime_t
2091330106Sdelphijbasedate_get_eracenter(void)
2092330106Sdelphij{
2093330106Sdelphij	time_t retv;
2094330106Sdelphij	retv  = (time_t)(s_baseday - NTP_TO_UNIX_DAYS);
2095330106Sdelphij	retv *= SECSPERDAY;
2096330106Sdelphij	retv += (UINT32_C(1) << 31);
2097330106Sdelphij	return retv;
2098330106Sdelphij}
2099330106Sdelphij
2100330106Sdelphijtime_t
2101330106Sdelphijbasedate_get_erabase(void)
2102330106Sdelphij{
2103330106Sdelphij	time_t retv;
2104330106Sdelphij	retv  = (time_t)(s_baseday - NTP_TO_UNIX_DAYS);
2105330106Sdelphij	retv *= SECSPERDAY;
2106330106Sdelphij	return retv;
2107330106Sdelphij}
2108330106Sdelphij
2109344884Scyuint32_t
2110344884Scybasedate_get_gpsweek(void)
2111344884Scy{
2112344884Scy    return s_gpsweek;
2113344884Scy}
2114344884Scy
2115344884Scyuint32_t
2116344884Scybasedate_expand_gpsweek(
2117344884Scy    unsigned short weekno
2118344884Scy    )
2119344884Scy{
2120344884Scy    /* We do a fast modulus expansion here. Since all quantities are
2121344884Scy     * unsigned and we cannot go before the start of the GPS epoch
2122344884Scy     * anyway, and since the truncated GPS week number is 10 bit, the
2123344884Scy     * expansion becomes a simple sub/and/add sequence.
2124344884Scy     */
2125344884Scy    #if GPSWEEKS != 1024
2126344884Scy    # error GPSWEEKS defined wrong -- should be 1024!
2127344884Scy    #endif
2128358659Scy
2129344884Scy    uint32_t diff;
2130344884Scy    diff = ((uint32_t)weekno - s_gpsweek) & (GPSWEEKS - 1);
2131344884Scy    return s_gpsweek + diff;
2132344884Scy}
2133344884Scy
2134358659Scy/*
2135358659Scy * ====================================================================
2136358659Scy * misc. helpers
2137358659Scy * ====================================================================
2138358659Scy */
2139358659Scy
2140358659Scy/* --------------------------------------------------------------------
2141358659Scy * reconstruct the centrury from a truncated date and a day-of-week
2142358659Scy *
2143358659Scy * Given a date with truncated year (2-digit, 0..99) and a day-of-week
2144358659Scy * from 1(Mon) to 7(Sun), recover the full year between 1900AD and 2300AD.
2145358659Scy */
2146358659Scyint32_t
2147358659Scyntpcal_expand_century(
2148358659Scy	uint32_t y,
2149358659Scy	uint32_t m,
2150358659Scy	uint32_t d,
2151358659Scy	uint32_t wd)
2152358659Scy{
2153358659Scy	/* This algorithm is short but tricky... It's related to
2154358659Scy	 * Zeller's congruence, partially done backwards.
2155358659Scy	 *
2156358659Scy	 * A few facts to remember:
2157358659Scy	 *  1) The Gregorian calendar has a cycle of 400 years.
2158358659Scy	 *  2) The weekday of the 1st day of a century shifts by 5 days
2159358659Scy	 *     during a great cycle.
2160358659Scy	 *  3) For calendar math, a century starts with the 1st year,
2161358659Scy	 *     which is year 1, !not! zero.
2162358659Scy	 *
2163358659Scy	 * So we start with taking the weekday difference (mod 7)
2164358659Scy	 * between the truncated date (which is taken as an absolute
2165358659Scy	 * date in the 1st century in the proleptic calendar) and the
2166358659Scy	 * weekday given.
2167358659Scy	 *
2168358659Scy	 * When dividing this residual by 5, we obtain the number of
2169358659Scy	 * centuries to add to the base. But since the residual is (mod
2170358659Scy	 * 7), we have to make this an exact division by multiplication
2171358659Scy	 * with the modular inverse of 5 (mod 7), which is 3:
2172358659Scy	 *    3*5 === 1 (mod 7).
2173358659Scy	 *
2174358659Scy	 * If this yields a result of 4/5/6, the given date/day-of-week
2175358659Scy	 * combination is impossible, and we return zero as resulting
2176358659Scy	 * year to indicate failure.
2177358659Scy	 *
2178358659Scy	 * Then we remap the century to the range starting with year
2179358659Scy	 * 1900.
2180358659Scy	 */
2181358659Scy
2182358659Scy	uint32_t c;
2183358659Scy
2184358659Scy	/* check basic constraints */
2185358659Scy	if ((y >= 100u) || (--m >= 12u) || (--d >= 31u))
2186358659Scy		return 0;
2187358659Scy
2188358659Scy	if ((m += 10u) >= 12u)		/* shift base to prev. March,1st */
2189358659Scy		m -= 12u;
2190358659Scy	else if (--y >= 100u)
2191358659Scy		y += 100u;
2192358659Scy	d += y + (y >> 2) + 2u;		/* year share */
2193358659Scy	d += (m * 83u + 16u) >> 5;	/* month share */
2194358659Scy
2195358659Scy	/* get (wd - d), shifted to positive value, and multiply with
2196358659Scy	 * 3(mod 7). (Exact division, see to comment)
2197358659Scy	 * Note: 1) d <= 184 at this point.
2198358659Scy	 *	 2) 252 % 7 == 0, but 'wd' is off by one since we did
2199358659Scy	 *	    '--d' above, so we add just 251 here!
2200358659Scy	 */
2201358659Scy	c = u32mod7(3 * (251u + wd - d));
2202358659Scy	if (c > 3u)
2203358659Scy		return 0;
2204358659Scy
2205358659Scy	if ((m > 9u) && (++y >= 100u)) {/* undo base shift */
2206358659Scy		y -= 100u;
2207358659Scy		c = (c + 1) & 3u;
2208358659Scy	}
2209358659Scy	y += (c * 100u);		/* combine into 1st cycle */
2210358659Scy	y += (y < 300u) ? 2000 : 1600;	/* map to destination era */
2211358659Scy	return (int)y;
2212358659Scy}
2213358659Scy
2214358659Scychar *
2215358659Scyntpcal_iso8601std(
2216358659Scy	char *		buf,
2217358659Scy	size_t		len,
2218358659Scy	TcCivilDate *	cdp
2219358659Scy	)
2220358659Scy{
2221358659Scy	if (!buf) {
2222358659Scy		LIB_GETBUF(buf);
2223358659Scy		len = LIB_BUFLENGTH;
2224358659Scy	}
2225358659Scy	if (len) {
2226358659Scy		len = snprintf(buf, len, "%04u-%02u-%02uT%02u:%02u:%02u",
2227358659Scy			       cdp->year, cdp->month, cdp->monthday,
2228358659Scy			       cdp->hour, cdp->minute, cdp->second);
2229358659Scy		if (len < 0)
2230358659Scy			*buf = '\0';
2231358659Scy	}
2232358659Scy	return buf;
2233358659Scy}
2234358659Scy
2235275970Scy/* -*-EOF-*- */
2236