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