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