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