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