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