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 */ 728 jd->weekday = rd % 7; 729 if (jd->weekday >= 7) /* unsigned! */ 730 jd->weekday += 7; 731 732 split = ntpcal_split_eradays(rd - 1, &leaps); 733 retv = leaps; 734 /* get year and day-of-year */ 735 jd->year = (uint16_t)split.hi + 1; 736 if (jd->year != split.hi + 1) { 737 jd->year = 0; 738 retv = -1; /* bletch. overflow trouble. */ 739 } 740 jd->yearday = (uint16_t)split.lo + 1; 741 742 /* convert to month and mday */ 743 split = ntpcal_split_yeardays(split.lo, leaps); 744 jd->month = (uint8_t)split.hi + 1; 745 jd->monthday = (uint8_t)split.lo + 1; 746 747 return retv ? retv : leaps; 748 } 749 750 /* 751 *--------------------------------------------------------------------- 752 * Convert a RD into the date part of a 'struct tm'. 753 *--------------------------------------------------------------------- 754 */ 755 int 756 ntpcal_rd_to_tm( 757 struct tm *utm, 758 int32_t rd 759 ) 760 { 761 ntpcal_split split; 762 int leaps; 763 764 leaps = 0; 765 /* get day-of-week first */ 766 utm->tm_wday = rd % 7; 767 if (utm->tm_wday < 0) 768 utm->tm_wday += 7; 769 770 /* get year and day-of-year */ 771 split = ntpcal_split_eradays(rd - 1, &leaps); 772 utm->tm_year = split.hi - 1899; 773 utm->tm_yday = split.lo; /* 0-based */ 774 775 /* convert to month and mday */ 776 split = ntpcal_split_yeardays(split.lo, leaps); 777 utm->tm_mon = split.hi; /* 0-based */ 778 utm->tm_mday = split.lo + 1; /* 1-based */ 779 780 return leaps; 781 } 782 783 /* 784 *--------------------------------------------------------------------- 785 * Take a value of seconds since midnight and split it into hhmmss in a 786 * 'struct calendar'. 787 *--------------------------------------------------------------------- 788 */ 789 int32_t 790 ntpcal_daysec_to_date( 791 struct calendar *jd, 792 int32_t sec 793 ) 794 { 795 int32_t days; 796 int ts[3]; 797 798 days = priv_timesplit(ts, sec); 799 jd->hour = (uint8_t)ts[0]; 800 jd->minute = (uint8_t)ts[1]; 801 jd->second = (uint8_t)ts[2]; 802 803 return days; 804 } 805 806 /* 807 *--------------------------------------------------------------------- 808 * Take a value of seconds since midnight and split it into hhmmss in a 809 * 'struct tm'. 810 *--------------------------------------------------------------------- 811 */ 812 int32_t 813 ntpcal_daysec_to_tm( 814 struct tm *utm, 815 int32_t sec 816 ) 817 { 818 int32_t days; 819 int32_t ts[3]; 820 821 days = priv_timesplit(ts, sec); 822 utm->tm_hour = ts[0]; 823 utm->tm_min = ts[1]; 824 utm->tm_sec = ts[2]; 825 826 return days; 827 } 828 829 /* 830 *--------------------------------------------------------------------- 831 * take a split representation for day/second-of-day and day offset 832 * and convert it to a 'struct calendar'. The seconds will be normalised 833 * into the range of a day, and the day will be adjusted accordingly. 834 * 835 * returns >0 if the result is in a leap year, 0 if in a regular 836 * year and <0 if the result did not fit into the calendar struct. 837 *--------------------------------------------------------------------- 838 */ 839 int 840 ntpcal_daysplit_to_date( 841 struct calendar *jd, 842 const ntpcal_split *ds, 843 int32_t dof 844 ) 845 { 846 dof += ntpcal_daysec_to_date(jd, ds->lo); 847 return ntpcal_rd_to_date(jd, ds->hi + dof); 848 } 849 850 /* 851 *--------------------------------------------------------------------- 852 * take a split representation for day/second-of-day and day offset 853 * and convert it to a 'struct tm'. The seconds will be normalised 854 * into the range of a day, and the day will be adjusted accordingly. 855 * 856 * returns 1 if the result is in a leap year and zero if in a regular 857 * year. 858 *--------------------------------------------------------------------- 859 */ 860 int 861 ntpcal_daysplit_to_tm( 862 struct tm *utm, 863 const ntpcal_split *ds , 864 int32_t dof 865 ) 866 { 867 dof += ntpcal_daysec_to_tm(utm, ds->lo); 868 869 return ntpcal_rd_to_tm(utm, ds->hi + dof); 870 } 871 872 /* 873 *--------------------------------------------------------------------- 874 * Take a UN*X time and convert to a calendar structure. 875 *--------------------------------------------------------------------- 876 */ 877 int 878 ntpcal_time_to_date( 879 struct calendar *jd, 880 const vint64 *ts 881 ) 882 { 883 ntpcal_split ds; 884 885 ds = ntpcal_daysplit(ts); 886 ds.hi += ntpcal_daysec_to_date(jd, ds.lo); 887 ds.hi += DAY_UNIX_STARTS; 888 889 return ntpcal_rd_to_date(jd, ds.hi); 890 } 891 892 893 /* 894 * ================================================================== 895 * 896 * merging composite entities 897 * 898 * ================================================================== 899 */ 900 901 /* 902 *--------------------------------------------------------------------- 903 * Merge a number of days and a number of seconds into seconds, 904 * expressed in 64 bits to avoid overflow. 905 *--------------------------------------------------------------------- 906 */ 907 vint64 908 ntpcal_dayjoin( 909 int32_t days, 910 int32_t secs 911 ) 912 { 913 vint64 res; 914 915 #ifdef HAVE_INT64 916 917 res.q_s = days; 918 res.q_s *= SECSPERDAY; 919 res.q_s += secs; 920 921 #else 922 923 uint32_t p1, p2; 924 int isneg; 925 926 /* 927 * res = days *86400 + secs, using manual 16/32 bit 928 * multiplications and shifts. 929 */ 930 isneg = (days < 0); 931 if (isneg) 932 days = -days; 933 934 /* assemble days * 675 */ 935 res.D_s.lo = (days & 0xFFFF) * 675u; 936 res.D_s.hi = 0; 937 p1 = (days >> 16) * 675u; 938 p2 = p1 >> 16; 939 p1 = p1 << 16; 940 M_ADD(res.D_s.hi, res.D_s.lo, p2, p1); 941 942 /* mul by 128, using shift */ 943 res.D_s.hi = (res.D_s.hi << 7) | (res.D_s.lo >> 25); 944 res.D_s.lo = (res.D_s.lo << 7); 945 946 /* fix sign */ 947 if (isneg) 948 M_NEG(res.D_s.hi, res.D_s.lo); 949 950 /* properly add seconds */ 951 p2 = 0; 952 if (secs < 0) { 953 p1 = (uint32_t)-secs; 954 M_NEG(p2, p1); 955 } else { 956 p1 = (uint32_t)secs; 957 } 958 M_ADD(res.D_s.hi, res.D_s.lo, p2, p1); 959 960 #endif 961 962 return res; 963 } 964 965 /* 966 *--------------------------------------------------------------------- 967 * Convert elapsed years in Era into elapsed days in Era. 968 * 969 * To accomodate for negative values of years, floor division would be 970 * required for all division operations. This can be eased by first 971 * splitting the years into full 400-year cycles and years in the 972 * cycle. Only this operation must be coded as a full floor division; as 973 * the years in the cycle is a non-negative number, all other divisions 974 * can be regular truncated divisions. 975 *--------------------------------------------------------------------- 976 */ 977 int32_t 978 ntpcal_days_in_years( 979 int32_t years 980 ) 981 { 982 int32_t cycle; /* full gregorian cycle */ 983 984 /* split off full calendar cycles, using floor division */ 985 cycle = years / 400; 986 years = years % 400; 987 if (years < 0) { 988 cycle -= 1; 989 years += 400; 990 } 991 992 /* 993 * Calculate days in cycle. years now is a non-negative number, 994 * holding the number of years in the 400-year cycle. 995 */ 996 return cycle * GREGORIAN_CYCLE_DAYS 997 + years * DAYSPERYEAR /* days inregular years */ 998 + years / 4 /* 4 year leap rule */ 999 - years / 100; /* 100 year leap rule */ 1000 /* the 400-year rule does not apply due to full-cycle split-off */ 1001 } 1002 1003 /* 1004 *--------------------------------------------------------------------- 1005 * Convert a number of elapsed month in a year into elapsed days in year. 1006 * 1007 * The month will be normalized, and 'res.hi' will contain the 1008 * excessive years that must be considered when converting the years, 1009 * while 'res.lo' will contain the number of elapsed days since start 1010 * of the year. 1011 * 1012 * This code uses the shifted-month-approach to convert month to days, 1013 * because then there is no need to have explicit leap year 1014 * information. The slight disadvantage is that for most month values 1015 * the result is a negative value, and the year excess is one; the 1016 * conversion is then simply based on the start of the following year. 1017 *--------------------------------------------------------------------- 1018 */ 1019 ntpcal_split 1020 ntpcal_days_in_months( 1021 int32_t m 1022 ) 1023 { 1024 ntpcal_split res; 1025 1026 /* normalize month into range */ 1027 res.hi = 0; 1028 res.lo = m; 1029 if (res.lo < 0 || res.lo >= 12) { 1030 res.hi = res.lo / 12; 1031 res.lo = res.lo % 12; 1032 if (res.lo < 0) { 1033 res.hi -= 1; 1034 res.lo += 12; 1035 } 1036 } 1037 1038 /* add 10 month for year starting with march */ 1039 if (res.lo < 2) 1040 res.lo += 10; 1041 else { 1042 res.hi += 1; 1043 res.lo -= 2; 1044 } 1045 1046 /* get cummulated days in year with unshift */ 1047 res.lo = shift_month_table[res.lo] - 306; 1048 1049 return res; 1050 } 1051 1052 /* 1053 *--------------------------------------------------------------------- 1054 * Convert ELAPSED years/months/days of gregorian calendar to elapsed 1055 * days in Gregorian epoch. 1056 * 1057 * If you want to convert years and days-of-year, just give a month of 1058 * zero. 1059 *--------------------------------------------------------------------- 1060 */ 1061 int32_t 1062 ntpcal_edate_to_eradays( 1063 int32_t years, 1064 int32_t mons, 1065 int32_t mdays 1066 ) 1067 { 1068 ntpcal_split tmp; 1069 int32_t res; 1070 1071 if (mons) { 1072 tmp = ntpcal_days_in_months(mons); 1073 res = ntpcal_days_in_years(years + tmp.hi) + tmp.lo; 1074 } else 1075 res = ntpcal_days_in_years(years); 1076 res += mdays; 1077 1078 return res; 1079 } 1080 1081 /* 1082 *--------------------------------------------------------------------- 1083 * Convert ELAPSED years/months/days of gregorian calendar to elapsed 1084 * days in year. 1085 * 1086 * Note: This will give the true difference to the start of the given year, 1087 * even if months & days are off-scale. 1088 *--------------------------------------------------------------------- 1089 */ 1090 int32_t 1091 ntpcal_edate_to_yeardays( 1092 int32_t years, 1093 int32_t mons, 1094 int32_t mdays 1095 ) 1096 { 1097 ntpcal_split tmp; 1098 1099 if (0 <= mons && mons < 12) { 1100 years += 1; 1101 mdays += real_month_table[is_leapyear(years)][mons]; 1102 } else { 1103 tmp = ntpcal_days_in_months(mons); 1104 mdays += tmp.lo 1105 + ntpcal_days_in_years(years + tmp.hi) 1106 - ntpcal_days_in_years(years); 1107 } 1108 1109 return mdays; 1110 } 1111 1112 /* 1113 *--------------------------------------------------------------------- 1114 * Convert elapsed days and the hour/minute/second information into 1115 * total seconds. 1116 * 1117 * If 'isvalid' is not NULL, do a range check on the time specification 1118 * and tell if the time input is in the normal range, permitting for a 1119 * single leapsecond. 1120 *--------------------------------------------------------------------- 1121 */ 1122 int32_t 1123 ntpcal_etime_to_seconds( 1124 int32_t hours, 1125 int32_t minutes, 1126 int32_t seconds 1127 ) 1128 { 1129 int32_t res; 1130 1131 res = (hours * MINSPERHR + minutes) * SECSPERMIN + seconds; 1132 1133 return res; 1134 } 1135 1136 /* 1137 *--------------------------------------------------------------------- 1138 * Convert the date part of a 'struct tm' (that is, year, month, 1139 * day-of-month) into the RD of that day. 1140 *--------------------------------------------------------------------- 1141 */ 1142 int32_t 1143 ntpcal_tm_to_rd( 1144 const struct tm *utm 1145 ) 1146 { 1147 return ntpcal_edate_to_eradays(utm->tm_year + 1899, 1148 utm->tm_mon, 1149 utm->tm_mday - 1) + 1; 1150 } 1151 1152 /* 1153 *--------------------------------------------------------------------- 1154 * Convert the date part of a 'struct calendar' (that is, year, month, 1155 * day-of-month) into the RD of that day. 1156 *--------------------------------------------------------------------- 1157 */ 1158 int32_t 1159 ntpcal_date_to_rd( 1160 const struct calendar *jd 1161 ) 1162 { 1163 return ntpcal_edate_to_eradays((int32_t)jd->year - 1, 1164 (int32_t)jd->month - 1, 1165 (int32_t)jd->monthday - 1) + 1; 1166 } 1167 1168 /* 1169 *--------------------------------------------------------------------- 1170 * convert a year number to rata die of year start 1171 *--------------------------------------------------------------------- 1172 */ 1173 int32_t 1174 ntpcal_year_to_ystart( 1175 int32_t year 1176 ) 1177 { 1178 return ntpcal_days_in_years(year - 1) + 1; 1179 } 1180 1181 /* 1182 *--------------------------------------------------------------------- 1183 * For a given RD, get the RD of the associated year start, 1184 * that is, the RD of the last January,1st on or before that day. 1185 *--------------------------------------------------------------------- 1186 */ 1187 int32_t 1188 ntpcal_rd_to_ystart( 1189 int32_t rd 1190 ) 1191 { 1192 /* 1193 * Rather simple exercise: split the day number into elapsed 1194 * years and elapsed days, then remove the elapsed days from the 1195 * input value. Nice'n sweet... 1196 */ 1197 return rd - ntpcal_split_eradays(rd - 1, NULL).lo; 1198 } 1199 1200 /* 1201 *--------------------------------------------------------------------- 1202 * For a given RD, get the RD of the associated month start. 1203 *--------------------------------------------------------------------- 1204 */ 1205 int32_t 1206 ntpcal_rd_to_mstart( 1207 int32_t rd 1208 ) 1209 { 1210 ntpcal_split split; 1211 int leaps; 1212 1213 split = ntpcal_split_eradays(rd - 1, &leaps); 1214 split = ntpcal_split_yeardays(split.lo, leaps); 1215 1216 return rd - split.lo; 1217 } 1218 1219 /* 1220 *--------------------------------------------------------------------- 1221 * take a 'struct calendar' and get the seconds-of-day from it. 1222 *--------------------------------------------------------------------- 1223 */ 1224 int32_t 1225 ntpcal_date_to_daysec( 1226 const struct calendar *jd 1227 ) 1228 { 1229 return ntpcal_etime_to_seconds(jd->hour, jd->minute, 1230 jd->second); 1231 } 1232 1233 /* 1234 *--------------------------------------------------------------------- 1235 * take a 'struct tm' and get the seconds-of-day from it. 1236 *--------------------------------------------------------------------- 1237 */ 1238 int32_t 1239 ntpcal_tm_to_daysec( 1240 const struct tm *utm 1241 ) 1242 { 1243 return ntpcal_etime_to_seconds(utm->tm_hour, utm->tm_min, 1244 utm->tm_sec); 1245 } 1246 1247 /* 1248 *--------------------------------------------------------------------- 1249 * take a 'struct calendar' and convert it to a 'time_t' 1250 *--------------------------------------------------------------------- 1251 */ 1252 time_t 1253 ntpcal_date_to_time( 1254 const struct calendar *jd 1255 ) 1256 { 1257 vint64 join; 1258 int32_t days, secs; 1259 1260 days = ntpcal_date_to_rd(jd) - DAY_UNIX_STARTS; 1261 secs = ntpcal_date_to_daysec(jd); 1262 join = ntpcal_dayjoin(days, secs); 1263 1264 return vint64_to_time(&join); 1265 } 1266 1267 1268 /* 1269 * ================================================================== 1270 * 1271 * extended and unchecked variants of caljulian/caltontp 1272 * 1273 * ================================================================== 1274 */ 1275 int 1276 ntpcal_ntp64_to_date( 1277 struct calendar *jd, 1278 const vint64 *ntp 1279 ) 1280 { 1281 ntpcal_split ds; 1282 1283 ds = ntpcal_daysplit(ntp); 1284 ds.hi += ntpcal_daysec_to_date(jd, ds.lo); 1285 1286 return ntpcal_rd_to_date(jd, ds.hi + DAY_NTP_STARTS); 1287 } 1288 1289 int 1290 ntpcal_ntp_to_date( 1291 struct calendar *jd, 1292 uint32_t ntp, 1293 const time_t *piv 1294 ) 1295 { 1296 vint64 ntp64; 1297 1298 /* 1299 * Unfold ntp time around current time into NTP domain. Split 1300 * into days and seconds, shift days into CE domain and 1301 * process the parts. 1302 */ 1303 ntp64 = ntpcal_ntp_to_ntp(ntp, piv); 1304 return ntpcal_ntp64_to_date(jd, &ntp64); 1305 } 1306 1307 1308 vint64 1309 ntpcal_date_to_ntp64( 1310 const struct calendar *jd 1311 ) 1312 { 1313 /* 1314 * Convert date to NTP. Ignore yearday, use d/m/y only. 1315 */ 1316 return ntpcal_dayjoin(ntpcal_date_to_rd(jd) - DAY_NTP_STARTS, 1317 ntpcal_date_to_daysec(jd)); 1318 } 1319 1320 1321 uint32_t 1322 ntpcal_date_to_ntp( 1323 const struct calendar *jd 1324 ) 1325 { 1326 /* 1327 * Get lower half of 64-bit NTP timestamp from date/time. 1328 */ 1329 return ntpcal_date_to_ntp64(jd).d_s.lo; 1330 } 1331 1332 1333 1334 /* 1335 * ================================================================== 1336 * 1337 * day-of-week calculations 1338 * 1339 * ================================================================== 1340 */ 1341 /* 1342 * Given a RataDie and a day-of-week, calculate a RDN that is reater-than, 1343 * greater-or equal, closest, less-or-equal or less-than the given RDN 1344 * and denotes the given day-of-week 1345 */ 1346 int32_t 1347 ntpcal_weekday_gt( 1348 int32_t rdn, 1349 int32_t dow 1350 ) 1351 { 1352 return ntpcal_periodic_extend(rdn+1, dow, 7); 1353 } 1354 1355 int32_t 1356 ntpcal_weekday_ge( 1357 int32_t rdn, 1358 int32_t dow 1359 ) 1360 { 1361 return ntpcal_periodic_extend(rdn, dow, 7); 1362 } 1363 1364 int32_t 1365 ntpcal_weekday_close( 1366 int32_t rdn, 1367 int32_t dow 1368 ) 1369 { 1370 return ntpcal_periodic_extend(rdn-3, dow, 7); 1371 } 1372 1373 int32_t 1374 ntpcal_weekday_le( 1375 int32_t rdn, 1376 int32_t dow 1377 ) 1378 { 1379 return ntpcal_periodic_extend(rdn, dow, -7); 1380 } 1381 1382 int32_t 1383 ntpcal_weekday_lt( 1384 int32_t rdn, 1385 int32_t dow 1386 ) 1387 { 1388 return ntpcal_periodic_extend(rdn-1, dow, -7); 1389 } 1390 1391 /* 1392 * ================================================================== 1393 * 1394 * ISO week-calendar conversions 1395 * 1396 * The ISO8601 calendar defines a calendar of years, weeks and weekdays. 1397 * It is related to the Gregorian calendar, and a ISO year starts at the 1398 * Monday closest to Jan,1st of the corresponding Gregorian year. A ISO 1399 * calendar year has always 52 or 53 weeks, and like the Grogrian 1400 * calendar the ISO8601 calendar repeats itself every 400 years, or 1401 * 146097 days, or 20871 weeks. 1402 * 1403 * While it is possible to write ISO calendar functions based on the 1404 * Gregorian calendar functions, the following implementation takes a 1405 * different approach, based directly on years and weeks. 1406 * 1407 * Analysis of the tabulated data shows that it is not possible to 1408 * interpolate from years to weeks over a full 400 year range; cyclic 1409 * shifts over 400 years do not provide a solution here. But it *is* 1410 * possible to interpolate over every single century of the 400-year 1411 * cycle. (The centennial leap year rule seems to be the culprit here.) 1412 * 1413 * It can be shown that a conversion from years to weeks can be done 1414 * using a linear transformation of the form 1415 * 1416 * w = floor( y * a + b ) 1417 * 1418 * where the slope a must hold to 1419 * 1420 * 52.1780821918 <= a < 52.1791044776 1421 * 1422 * and b must be chosen according to the selected slope and the number 1423 * of the century in a 400-year period. 1424 * 1425 * The inverse calculation can also be done in this way. Careful scaling 1426 * provides an unlimited set of integer coefficients a,k,b that enable 1427 * us to write the calulation in the form 1428 * 1429 * w = (y * a + b ) / k 1430 * y = (w * a' + b') / k' 1431 * 1432 * In this implementation the values of k and k' are chosen to be 1433 * smallest possible powers of two, so the division can be implemented 1434 * as shifts if the optimiser chooses to do so. 1435 * 1436 * ================================================================== 1437 */ 1438 1439 /* 1440 * Given a number of elapsed (ISO-)years since the begin of the 1441 * christian era, return the number of elapsed weeks corresponding to 1442 * the number of years. 1443 */ 1444 int32_t 1445 isocal_weeks_in_years( 1446 int32_t years 1447 ) 1448 { 1449 /* 1450 * use: w = (y * 53431 + b[c]) / 1024 as interpolation 1451 */ 1452 static const int32_t bctab[4] = { 449, 157, 889, 597 }; 1453 int32_t cycle; /* full gregorian cycle */ 1454 int32_t cents; /* full centuries */ 1455 int32_t weeks; /* accumulated weeks */ 1456 1457 /* split off full calendar cycles, using floor division */ 1458 cycle = years / 400; 1459 years = years % 400; 1460 if (years < 0) { 1461 cycle -= 1; 1462 years += 400; 1463 } 1464 1465 /* split off full centuries */ 1466 cents = years / 100; 1467 years = years % 100; 1468 1469 /* 1470 * calculate elapsed weeks, taking into account that the 1471 * first, third and fourth century have 5218 weeks but the 1472 * second century falls short by one week. 1473 */ 1474 weeks = (years * 53431 + bctab[cents]) / 1024; 1475 1476 return cycle * GREGORIAN_CYCLE_WEEKS 1477 + cents * 5218 - (cents > 1) 1478 + weeks; 1479 } 1480 1481 /* 1482 * Given a number of elapsed weeks since the begin of the christian 1483 * era, split this number into the number of elapsed years in res.hi 1484 * and the excessive number of weeks in res.lo. (That is, res.lo is 1485 * the number of elapsed weeks in the remaining partial year.) 1486 */ 1487 ntpcal_split 1488 isocal_split_eraweeks( 1489 int32_t weeks 1490 ) 1491 { 1492 /* 1493 * use: y = (w * 157 + b[c]) / 8192 as interpolation 1494 */ 1495 static const int32_t bctab[4] = { 85, 131, 17, 62 }; 1496 ntpcal_split res; 1497 int32_t cents; 1498 1499 /* 1500 * split off 400-year cycles, using the fact that a 400-year 1501 * cycle has 146097 days, which is exactly 20871 weeks. 1502 */ 1503 res.hi = weeks / GREGORIAN_CYCLE_WEEKS; 1504 res.lo = weeks % GREGORIAN_CYCLE_WEEKS; 1505 if (res.lo < 0) { 1506 res.hi -= 1; 1507 res.lo += GREGORIAN_CYCLE_WEEKS; 1508 } 1509 res.hi *= 400; 1510 1511 /* 1512 * split off centuries, taking into account that the first, 1513 * third and fourth century have 5218 weeks but that the 1514 * second century falls short by one week. 1515 */ 1516 res.lo += (res.lo >= 10435); 1517 cents = res.lo / 5218; 1518 res.lo %= 5218; /* res.lo is weeks in century now */ 1519 1520 /* convert elapsed weeks in century to elapsed years and weeks */ 1521 res.lo = res.lo * 157 + bctab[cents]; 1522 res.hi += cents * 100 + res.lo / 8192; 1523 res.lo = (res.lo % 8192) / 157; 1524 1525 return res; 1526 } 1527 1528 /* 1529 * Given a second in the NTP time scale and a pivot, expand the NTP 1530 * time stamp around the pivot and convert into an ISO calendar time 1531 * stamp. 1532 */ 1533 int 1534 isocal_ntp64_to_date( 1535 struct isodate *id, 1536 const vint64 *ntp 1537 ) 1538 { 1539 ntpcal_split ds; 1540 int32_t ts[3]; 1541 1542 /* 1543 * Split NTP time into days and seconds, shift days into CE 1544 * domain and process the parts. 1545 */ 1546 ds = ntpcal_daysplit(ntp); 1547 1548 /* split time part */ 1549 ds.hi += priv_timesplit(ts, ds.lo); 1550 id->hour = (uint8_t)ts[0]; 1551 id->minute = (uint8_t)ts[1]; 1552 id->second = (uint8_t)ts[2]; 1553 1554 /* split date part */ 1555 ds.lo = ds.hi + DAY_NTP_STARTS - 1; /* elapsed era days */ 1556 ds.hi = ds.lo / 7; /* elapsed era weeks */ 1557 ds.lo = ds.lo % 7; /* elapsed week days */ 1558 if (ds.lo < 0) { /* floor division! */ 1559 ds.hi -= 1; 1560 ds.lo += 7; 1561 } 1562 id->weekday = (uint8_t)ds.lo + 1; /* weekday result */ 1563 1564 ds = isocal_split_eraweeks(ds.hi); /* elapsed years&week*/ 1565 id->year = (uint16_t)ds.hi + 1; /* shift to current */ 1566 id->week = (uint8_t )ds.lo + 1; 1567 1568 return (ds.hi >= 0 && ds.hi < 0x0000FFFF); 1569 } 1570 1571 int 1572 isocal_ntp_to_date( 1573 struct isodate *id, 1574 uint32_t ntp, 1575 const time_t *piv 1576 ) 1577 { 1578 vint64 ntp64; 1579 1580 /* 1581 * Unfold ntp time around current time into NTP domain, then 1582 * convert the full time stamp. 1583 */ 1584 ntp64 = ntpcal_ntp_to_ntp(ntp, piv); 1585 return isocal_ntp64_to_date(id, &ntp64); 1586 } 1587 1588 /* 1589 * Convert a ISO date spec into a second in the NTP time scale, 1590 * properly truncated to 32 bit. 1591 */ 1592 vint64 1593 isocal_date_to_ntp64( 1594 const struct isodate *id 1595 ) 1596 { 1597 int32_t weeks, days, secs; 1598 1599 weeks = isocal_weeks_in_years((int32_t)id->year - 1) 1600 + (int32_t)id->week - 1; 1601 days = weeks * 7 + (int32_t)id->weekday; 1602 /* days is RDN of ISO date now */ 1603 secs = ntpcal_etime_to_seconds(id->hour, id->minute, id->second); 1604 1605 return ntpcal_dayjoin(days - DAY_NTP_STARTS, secs); 1606 } 1607 1608 uint32_t 1609 isocal_date_to_ntp( 1610 const struct isodate *id 1611 ) 1612 { 1613 /* 1614 * Get lower half of 64-bit NTP timestamp from date/time. 1615 */ 1616 return isocal_date_to_ntp64(id).d_s.lo; 1617 } 1618 1619 /* -*-EOF-*- */ 1620