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