ntp_calendar.c revision 338530
138032Speter/* 2182352Sgshapiro * ntp_calendar.c - calendar and helper functions 364562Sgshapiro * 438032Speter * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project. 538032Speter * The contents of 'html/copyright.html' apply. 638032Speter * 738032Speter * -------------------------------------------------------------------- 838032Speter * Some notes on the implementation: 938032Speter * 1038032Speter * Calendar algorithms thrive on the division operation, which is one of 1138032Speter * the slowest numerical operations in any CPU. What saves us here from 1238032Speter * abysmal performance is the fact that all divisions are divisions by 1338032Speter * constant numbers, and most compilers can do this by a multiplication 1490792Sgshapiro * operation. But this might not work when using the div/ldiv/lldiv 1590792Sgshapiro * function family, because many compilers are not able to do inline 16168515Sgshapiro * expansion of the code with following optimisation for the 1790792Sgshapiro * constant-divider case. 1890792Sgshapiro * 1990792Sgshapiro * Also div/ldiv/lldiv are defined in terms of int/long/longlong, which 2038032Speter * are inherently target dependent. Nothing that could not be cured with 2190792Sgshapiro * autoconf, but still a mess... 22132943Sgshapiro * 2364562Sgshapiro * Furthermore, we need floor division in many places. C either leaves 2438032Speter * the division behaviour undefined (< C99) or demands truncation to 2538032Speter * zero (>= C99), so additional steps are required to make sure the 2638032Speter * algorithms work. The {l,ll}div function family is requested to 2764562Sgshapiro * truncate towards zero, which is also the wrong direction for our 2838032Speter * purpose. 29182352Sgshapiro * 3038032Speter * For all this, all divisions by constant are coded manually, even when 3138032Speter * there is a joined div/mod operation: The optimiser should sort that 3264562Sgshapiro * out, if possible. Most of the calculations are done with unsigned 3364562Sgshapiro * types, explicitely using two's complement arithmetics where 3464562Sgshapiro * necessary. This minimises the dependecies to compiler and target, 3564562Sgshapiro * while still giving reasonable to good performance. 3690792Sgshapiro * 3790792Sgshapiro * The implementation uses a few tricks that exploit properties of the 3890792Sgshapiro * two's complement: Floor division on negative dividents can be 3990792Sgshapiro * executed by using the one's complement of the divident. One's 4090792Sgshapiro * complement can be easily created using XOR and a mask. 4190792Sgshapiro * 4290792Sgshapiro * Finally, check for overflow conditions is minimal. There are only two 4390792Sgshapiro * calculation steps in the whole calendar that suffer from an internal 4490792Sgshapiro * overflow, and these conditions are checked: errno is set to EDOM and 4590792Sgshapiro * the results are clamped/saturated in this case. All other functions 4690792Sgshapiro * do not suffer from internal overflow and simply return the result 4790792Sgshapiro * truncated to 32 bits. 4877349Sgshapiro * 4990792Sgshapiro * This is a sacrifice made for execution speed. Since a 32-bit day 5090792Sgshapiro * counter covers +/- 5,879,610 years and the clamp limits the effective 5190792Sgshapiro * range to +/-2.9 million years, this should not pose a problem here. 5280785Sgshapiro * 5377349Sgshapiro */ 5490792Sgshapiro 5564562Sgshapiro#include <config.h> 5638032Speter#include <sys/types.h> 5738032Speter 5838032Speter#include "ntp_types.h" 5938032Speter#include "ntp_calendar.h" 6038032Speter#include "ntp_stdlib.h" 6138032Speter#include "ntp_fp.h" 6238032Speter#include "ntp_unixtime.h" 6338032Speter 6464562Sgshapiro/* For now, let's take the conservative approach: if the target property 6538032Speter * macros are not defined, check a few well-known compiler/architecture 6638032Speter * settings. Default is to assume that the representation of signed 6738032Speter * integers is unknown and shift-arithmetic-right is not available. 6838032Speter */ 6938032Speter#ifndef TARGET_HAS_2CPL 7038032Speter# if defined(__GNUC__) 7138032Speter# if defined(__i386__) || defined(__x86_64__) || defined(__arm__) 7290792Sgshapiro# define TARGET_HAS_2CPL 1 7338032Speter# else 7438032Speter# define TARGET_HAS_2CPL 0 7538032Speter# endif 7638032Speter# elif defined(_MSC_VER) 7738032Speter# if defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM) 7838032Speter# define TARGET_HAS_2CPL 1 7938032Speter# else 8038032Speter# define TARGET_HAS_2CPL 0 81111823Sgshapiro# endif 8238032Speter# else 8338032Speter# define TARGET_HAS_2CPL 0 8490792Sgshapiro# endif 8590792Sgshapiro#endif 8690792Sgshapiro 8790792Sgshapiro#ifndef TARGET_HAS_SAR 8890792Sgshapiro# define TARGET_HAS_SAR 0 8990792Sgshapiro#endif 9090792Sgshapiro 9138032Speter/* 9238032Speter *--------------------------------------------------------------------- 9338032Speter * replacing the 'time()' function 9438032Speter *--------------------------------------------------------------------- 9564562Sgshapiro */ 9638032Speter 9738032Speterstatic systime_func_ptr systime_func = &time; 9838032Speterstatic inline time_t now(void); 9990792Sgshapiro 10064562Sgshapiro 10190792Sgshapirosystime_func_ptr 10238032Speterntpcal_set_timefunc( 10338032Speter systime_func_ptr nfunc 10438032Speter ) 10564562Sgshapiro{ 10638032Speter systime_func_ptr res; 10790792Sgshapiro 10838032Speter res = systime_func; 10964562Sgshapiro if (NULL == nfunc) 11064562Sgshapiro nfunc = &time; 11164562Sgshapiro systime_func = nfunc; 11264562Sgshapiro 11364562Sgshapiro return res; 11464562Sgshapiro} 11564562Sgshapiro 11664562Sgshapiro 11764562Sgshapirostatic inline time_t 11890792Sgshapironow(void) 11990792Sgshapiro{ 12090792Sgshapiro return (*systime_func)(NULL); 12190792Sgshapiro} 12290792Sgshapiro 12390792Sgshapiro/* 12490792Sgshapiro *--------------------------------------------------------------------- 12564562Sgshapiro * Get sign extension mask and unsigned 2cpl rep for a signed integer 12690792Sgshapiro *--------------------------------------------------------------------- 12790792Sgshapiro */ 12890792Sgshapiro 12990792Sgshapirostatic inline uint32_t 13090792Sgshapiroint32_sflag( 13190792Sgshapiro const int32_t v) 132112810Sgshapiro{ 13390792Sgshapiro# if TARGET_HAS_2CPL && TARGET_HAS_SAR && SIZEOF_INT >= 4 13490792Sgshapiro 13590792Sgshapiro /* Let's assume that shift is the fastest way to get the sign 13690792Sgshapiro * extension of of a signed integer. This might not always be 13790792Sgshapiro * true, though -- On 8bit CPUs or machines without barrel 13890792Sgshapiro * shifter this will kill the performance. So we make sure 13990792Sgshapiro * we do this only if 'int' has at least 4 bytes. 14090792Sgshapiro */ 14190792Sgshapiro return (uint32_t)(v >> 31); 14290792Sgshapiro 14390792Sgshapiro# else 14490792Sgshapiro 14590792Sgshapiro /* This should be a rather generic approach for getting a sign 14690792Sgshapiro * extension mask... 14790792Sgshapiro */ 14890792Sgshapiro return UINT32_C(0) - (uint32_t)(v < 0); 14938032Speter 15038032Speter# endif 15138032Speter} 15238032Speter 15338032Speterstatic inline uint32_t 15438032Speterint32_to_uint32_2cpl( 15538032Speter const int32_t v) 15638032Speter{ 15738032Speter uint32_t vu; 15838032Speter 15938032Speter# if TARGET_HAS_2CPL 16038032Speter 16138032Speter /* Just copy through the 32 bits from the signed value if we're 16264562Sgshapiro * on a two's complement target. 16390792Sgshapiro */ 16490792Sgshapiro vu = (uint32_t)v; 16590792Sgshapiro 16664562Sgshapiro# else 16790792Sgshapiro 16890792Sgshapiro /* Convert from signed int to unsigned int two's complement. Do 16938032Speter * not make any assumptions about the representation of signed 17090792Sgshapiro * integers, but make sure signed integer overflow cannot happen 17190792Sgshapiro * here. A compiler on a two's complement target *might* find 17238032Speter * out that this is just a complicated cast (as above), but your 17338032Speter * mileage might vary. 17438032Speter */ 17564562Sgshapiro if (v < 0) 17664562Sgshapiro vu = ~(uint32_t)(-(v + 1)); 17790792Sgshapiro else 17890792Sgshapiro vu = (uint32_t)v; 17990792Sgshapiro 18090792Sgshapiro# endif 18190792Sgshapiro 18290792Sgshapiro return vu; 18390792Sgshapiro} 18490792Sgshapiro 18590792Sgshapirostatic inline int32_t 186132943Sgshapirouint32_2cpl_to_int32( 18790792Sgshapiro const uint32_t vu) 18864562Sgshapiro{ 18990792Sgshapiro int32_t v; 19038032Speter 19138032Speter# if TARGET_HAS_2CPL 19238032Speter 19390792Sgshapiro /* Just copy through the 32 bits from the unsigned value if 19466494Sgshapiro * we're on a two's complement target. 19590792Sgshapiro */ 19638032Speter v = (int32_t)vu; 19790792Sgshapiro 19838032Speter# else 19938032Speter 20038032Speter /* Convert to signed integer, making sure signed integer 20138032Speter * overflow cannot happen. Again, the optimiser might or might 20238032Speter * not find out that this is just a copy of 32 bits on a target 20390792Sgshapiro * with two's complement representation for signed integers. 20490792Sgshapiro */ 20590792Sgshapiro if (vu > INT32_MAX) 20638032Speter v = -(int32_t)(~vu) - 1; 20790792Sgshapiro else 20890792Sgshapiro v = (int32_t)vu; 20990792Sgshapiro 21090792Sgshapiro# endif 21190792Sgshapiro 21290792Sgshapiro return v; 21390792Sgshapiro} 21490792Sgshapiro 21590792Sgshapiro/* Some of the calculations need to multiply the input by 4 before doing 21690792Sgshapiro * a division. This can cause overflow and strange results. Therefore we 217110560Sgshapiro * clamp / saturate the input operand. And since we do the calculations 218110560Sgshapiro * in unsigned int with an extra sign flag/mask, we only loose one bit 219110560Sgshapiro * of the input value range. 220110560Sgshapiro */ 22138032Speterstatic inline uint32_t 22238032Speteruint32_saturate( 22338032Speter uint32_t vu, 22438032Speter uint32_t mu) 22538032Speter{ 22638032Speter static const uint32_t limit = UINT32_MAX/4u; 22790792Sgshapiro if ((mu ^ vu) > limit) { 22838032Speter vu = mu ^ limit; 22938032Speter errno = EDOM; 23038032Speter } 23138032Speter return vu; 23290792Sgshapiro} 23338032Speter 23438032Speter/* 235168515Sgshapiro *--------------------------------------------------------------------- 23638032Speter * Convert between 'time_t' and 'vint64' 23790792Sgshapiro *--------------------------------------------------------------------- 23890792Sgshapiro */ 23977349Sgshapirovint64 24090792Sgshapirotime_to_vint64( 24190792Sgshapiro const time_t * ptt 24290792Sgshapiro ) 24377349Sgshapiro{ 24490792Sgshapiro vint64 res; 24538032Speter time_t tt; 24690792Sgshapiro 24790792Sgshapiro tt = *ptt; 24864562Sgshapiro 24938032Speter# if SIZEOF_TIME_T <= 4 25038032Speter 25138032Speter res.D_s.hi = 0; 25238032Speter if (tt < 0) { 25338032Speter res.D_s.lo = (uint32_t)-tt; 25438032Speter M_NEG(res.D_s.hi, res.D_s.lo); 25538032Speter } else { 25638032Speter res.D_s.lo = (uint32_t)tt; 25738032Speter } 25838032Speter 25990792Sgshapiro# elif defined(HAVE_INT64) 26090792Sgshapiro 26138032Speter res.q_s = tt; 26290792Sgshapiro 26390792Sgshapiro# else 26438032Speter /* 26590792Sgshapiro * shifting negative signed quantities is compiler-dependent, so 26690792Sgshapiro * we better avoid it and do it all manually. And shifting more 26738032Speter * than the width of a quantity is undefined. Also a don't do! 26890792Sgshapiro */ 26990792Sgshapiro if (tt < 0) { 27038032Speter tt = -tt; 271132943Sgshapiro res.D_s.lo = (uint32_t)tt; 27238032Speter res.D_s.hi = (uint32_t)(tt >> 32); 273132943Sgshapiro M_NEG(res.D_s.hi, res.D_s.lo); 27438032Speter } else { 27538032Speter res.D_s.lo = (uint32_t)tt; 27690792Sgshapiro res.D_s.hi = (uint32_t)(tt >> 32); 27790792Sgshapiro } 27890792Sgshapiro 27964562Sgshapiro# endif 28090792Sgshapiro 28164562Sgshapiro return res; 28290792Sgshapiro} 28364562Sgshapiro 28464562Sgshapiro 28538032Spetertime_t 28690792Sgshapirovint64_to_time( 28790792Sgshapiro const vint64 *tv 28890792Sgshapiro ) 28990792Sgshapiro{ 29090792Sgshapiro time_t res; 29138032Speter 29290792Sgshapiro# if SIZEOF_TIME_T <= 4 29338032Speter 29490792Sgshapiro res = (time_t)tv->D_s.lo; 29590792Sgshapiro 29690792Sgshapiro# elif defined(HAVE_INT64) 29790792Sgshapiro 29890792Sgshapiro res = (time_t)tv->q_s; 29990792Sgshapiro 30038032Speter# else 30138032Speter 30238032Speter res = ((time_t)tv->d_s.hi << 32) | tv->D_s.lo; 30338032Speter 30464562Sgshapiro# endif 305182352Sgshapiro 306182352Sgshapiro return res; 307182352Sgshapiro} 30838032Speter 30938032Speter/* 31064562Sgshapiro *--------------------------------------------------------------------- 31138032Speter * Get the build date & time 312168515Sgshapiro *--------------------------------------------------------------------- 31338032Speter */ 31438032Speterint 31538032Speterntpcal_get_build_date( 31638032Speter struct calendar * jd 31790792Sgshapiro ) 31890792Sgshapiro{ 31938032Speter /* The C standard tells us the format of '__DATE__': 32090792Sgshapiro * 32190792Sgshapiro * __DATE__ The date of translation of the preprocessing 32238032Speter * translation unit: a character string literal of the form "Mmm 32338032Speter * dd yyyy", where the names of the months are the same as those 32464562Sgshapiro * generated by the asctime function, and the first character of 32538032Speter * dd is a space character if the value is less than 10. If the 32638032Speter * date of translation is not available, an 32790792Sgshapiro * implementation-defined valid date shall be supplied. 32864562Sgshapiro * 32938032Speter * __TIME__ The time of translation of the preprocessing 33090792Sgshapiro * translation unit: a character string literal of the form 33177349Sgshapiro * "hh:mm:ss" as in the time generated by the asctime 33294334Sgshapiro * function. If the time of translation is not available, an 33377349Sgshapiro * implementation-defined valid time shall be supplied. 33477349Sgshapiro * 33590792Sgshapiro * Note that MSVC declares DATE and TIME to be in the local time 33677349Sgshapiro * zone, while neither the C standard nor the GCC docs make any 33794334Sgshapiro * statement about this. As a result, we may be +/-12hrs off 33894334Sgshapiro * UTC. But for practical purposes, this should not be a 33994334Sgshapiro * problem. 34094334Sgshapiro * 34194334Sgshapiro */ 34290792Sgshapiro# ifdef MKREPRO_DATE 34338032Speter static const char build[] = MKREPRO_TIME "/" MKREPRO_DATE; 34438032Speter# else 34538032Speter static const char build[] = __TIME__ "/" __DATE__; 34638032Speter# endif 34738032Speter static const char mlist[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; 34838032Speter 34938032Speter char monstr[4]; 35038032Speter const char * cp; 35138032Speter unsigned short hour, minute, second, day, year; 35238032Speter /* Note: The above quantities are used for sscanf 'hu' format, 35338032Speter * so using 'uint16_t' is contra-indicated! 35464562Sgshapiro */ 35590792Sgshapiro 35690792Sgshapiro# ifdef DEBUG 35790792Sgshapiro static int ignore = 0; 35890792Sgshapiro# endif 35990792Sgshapiro 36090792Sgshapiro ZERO(*jd); 36190792Sgshapiro jd->year = 1970; 36290792Sgshapiro jd->month = 1; 36390792Sgshapiro jd->monthday = 1; 36490792Sgshapiro 36590792Sgshapiro# ifdef DEBUG 36690792Sgshapiro /* check environment if build date should be ignored */ 36790792Sgshapiro if (0 == ignore) { 36890792Sgshapiro const char * envstr; 36990792Sgshapiro envstr = getenv("NTPD_IGNORE_BUILD_DATE"); 37090792Sgshapiro ignore = 1 + (envstr && (!*envstr || !strcasecmp(envstr, "yes"))); 37190792Sgshapiro } 372132943Sgshapiro if (ignore > 1) 373132943Sgshapiro return FALSE; 374132943Sgshapiro# endif 375132943Sgshapiro 376132943Sgshapiro if (6 == sscanf(build, "%hu:%hu:%hu/%3s %hu %hu", 377132943Sgshapiro &hour, &minute, &second, monstr, &day, &year)) { 378132943Sgshapiro cp = strstr(mlist, monstr); 379132943Sgshapiro if (NULL != cp) { 380132943Sgshapiro jd->year = year; 38190792Sgshapiro jd->month = (uint8_t)((cp - mlist) / 3 + 1); 382112810Sgshapiro jd->monthday = (uint8_t)day; 38338032Speter jd->hour = (uint8_t)hour; 38438032Speter jd->minute = (uint8_t)minute; 38538032Speter jd->second = (uint8_t)second; 38638032Speter 38738032Speter return TRUE; 38890792Sgshapiro } 38994334Sgshapiro } 39094334Sgshapiro 39138032Speter return FALSE; 39290792Sgshapiro} 39390792Sgshapiro 39490792Sgshapiro 39590792Sgshapiro/* 39690792Sgshapiro *--------------------------------------------------------------------- 39790792Sgshapiro * basic calendar stuff 39890792Sgshapiro *--------------------------------------------------------------------- 39990792Sgshapiro */ 40090792Sgshapiro 40190792Sgshapiro/* month table for a year starting with March,1st */ 40290792Sgshapirostatic const uint16_t shift_month_table[13] = { 40390792Sgshapiro 0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337, 366 40490792Sgshapiro}; 40538032Speter 40690792Sgshapiro/* month tables for years starting with January,1st; regular & leap */ 407182352Sgshapirostatic const uint16_t real_month_table[2][13] = { 408182352Sgshapiro /* -*- table for regular years -*- */ 409182352Sgshapiro { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, 410182352Sgshapiro /* -*- table for leap years -*- */ 411182352Sgshapiro { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } 412182352Sgshapiro}; 413182352Sgshapiro 41490792Sgshapiro/* 41590792Sgshapiro * Some notes on the terminology: 41690792Sgshapiro * 41790792Sgshapiro * We use the proleptic Gregorian calendar, which is the Gregorian 41890792Sgshapiro * calendar extended in both directions ad infinitum. This totally 41990792Sgshapiro * disregards the fact that this calendar was invented in 1582, and 42090792Sgshapiro * was adopted at various dates over the world; sometimes even after 42190792Sgshapiro * the start of the NTP epoch. 42290792Sgshapiro * 42390792Sgshapiro * Normally date parts are given as current cycles, while time parts 42438032Speter * are given as elapsed cycles: 42590792Sgshapiro * 42690792Sgshapiro * 1970-01-01/03:04:05 means 'IN the 1970st. year, IN the first month, 427132943Sgshapiro * ON the first day, with 3hrs, 4minutes and 5 seconds elapsed. 428132943Sgshapiro * 429132943Sgshapiro * The basic calculations for this calendar implementation deal with 430132943Sgshapiro * ELAPSED date units, which is the number of full years, full months 431132943Sgshapiro * and full days before a date: 1970-01-01 would be (1969, 0, 0) in 432132943Sgshapiro * that notation. 433132943Sgshapiro * 434132943Sgshapiro * To ease the numeric computations, month and day values outside the 435132943Sgshapiro * normal range are acceptable: 2001-03-00 will be treated as the day 436132943Sgshapiro * before 2001-03-01, 2000-13-32 will give the same result as 437132943Sgshapiro * 2001-02-01 and so on. 438132943Sgshapiro * 439132943Sgshapiro * 'rd' or 'RD' is used as an abbreviation for the latin 'rata die' 440132943Sgshapiro * (day number). This is the number of days elapsed since 0000-12-31 441132943Sgshapiro * in the proleptic Gregorian calendar. The begin of the Christian Era 442132943Sgshapiro * (0001-01-01) is RD(1). 443132943Sgshapiro */ 444132943Sgshapiro 445132943Sgshapiro/* 446132943Sgshapiro * ==================================================================== 447132943Sgshapiro * 44890792Sgshapiro * General algorithmic stuff 44990792Sgshapiro * 45038032Speter * ==================================================================== 451132943Sgshapiro */ 45290792Sgshapiro 45390792Sgshapiro/* 45438032Speter *--------------------------------------------------------------------- 45564562Sgshapiro * Do a periodic extension of 'value' around 'pivot' with a period of 45664562Sgshapiro * 'cycle'. 45790792Sgshapiro * 45864562Sgshapiro * The result 'res' is a number that holds to the following properties: 45964562Sgshapiro * 46064562Sgshapiro * 1) res MOD cycle == value MOD cycle 461112810Sgshapiro * 2) pivot <= res < pivot + cycle 462112810Sgshapiro * (replace </<= with >/>= for negative cycles) 463112810Sgshapiro * 464112810Sgshapiro * where 'MOD' denotes the modulo operator for FLOOR DIVISION, which 465112810Sgshapiro * is not the same as the '%' operator in C: C requires division to be 466112810Sgshapiro * a truncated division, where remainder and dividend have the same 467112810Sgshapiro * sign if the remainder is not zero, whereas floor division requires 468132943Sgshapiro * divider and modulus to have the same sign for a non-zero modulus. 46964562Sgshapiro * 47090792Sgshapiro * This function has some useful applications: 47190792Sgshapiro * 47290792Sgshapiro * + let Y be a calendar year and V a truncated 2-digit year: then 47364562Sgshapiro * periodic_extend(Y-50, V, 100) 47464562Sgshapiro * is the closest expansion of the truncated year with respect to 47590792Sgshapiro * the full year, that is a 4-digit year with a difference of less 47690792Sgshapiro * than 50 years to the year Y. ("century unfolding") 47790792Sgshapiro * 47890792Sgshapiro * + let T be a UN*X time stamp and V be seconds-of-day: then 47964562Sgshapiro * perodic_extend(T-43200, V, 86400) 48038032Speter * is a time stamp that has the same seconds-of-day as the input 48138032Speter * value, with an absolute difference to T of <= 12hrs. ("day 48238032Speter * unfolding") 48338032Speter * 48490792Sgshapiro * + Wherever you have a truncated periodic value and a non-truncated 48590792Sgshapiro * base value and you want to match them somehow... 48690792Sgshapiro * 48790792Sgshapiro * Basically, the function delivers 'pivot + (value - pivot) % cycle', 48890792Sgshapiro * but the implementation takes some pains to avoid internal signed 489132943Sgshapiro * integer overflows in the '(value - pivot) % cycle' part and adheres 49090792Sgshapiro * to the floor division convention. 491168515Sgshapiro * 49290792Sgshapiro * If 64bit scalars where available on all intended platforms, writing a 49390792Sgshapiro * version that uses 64 bit ops would be easy; writing a general 49477349Sgshapiro * division routine for 64bit ops on a platform that can only do 49564562Sgshapiro * 32/16bit divisions and is still performant is a bit more 49664562Sgshapiro * difficult. Since most usecases can be coded in a way that does only 49777349Sgshapiro * require the 32-bit version a 64bit version is NOT provided here. 49877349Sgshapiro *--------------------------------------------------------------------- 49977349Sgshapiro */ 50077349Sgshapiroint32_t 50177349Sgshapirontpcal_periodic_extend( 50277349Sgshapiro int32_t pivot, 50364562Sgshapiro int32_t value, 50464562Sgshapiro int32_t cycle 50564562Sgshapiro ) 50664562Sgshapiro{ 50764562Sgshapiro uint32_t diff; 50864562Sgshapiro char cpl = 0; /* modulo complement flag */ 50977349Sgshapiro char neg = 0; /* sign change flag */ 51064562Sgshapiro 51164562Sgshapiro /* make the cycle positive and adjust the flags */ 51238032Speter if (cycle < 0) { 51338032Speter cycle = - cycle; 51438032Speter neg ^= 1; 51538032Speter cpl ^= 1; 51638032Speter } 51738032Speter /* guard against div by zero or one */ 51838032Speter if (cycle > 1) { 51938032Speter /* 52038032Speter * Get absolute difference as unsigned quantity and 52138032Speter * the complement flag. This is done by always 52238032Speter * subtracting the smaller value from the bigger 52338032Speter * one. 52438032Speter */ 52538032Speter if (value >= pivot) { 52690792Sgshapiro diff = int32_to_uint32_2cpl(value) 52738032Speter - int32_to_uint32_2cpl(pivot); 52890792Sgshapiro } else { 52990792Sgshapiro diff = int32_to_uint32_2cpl(pivot) 530159609Sgshapiro - int32_to_uint32_2cpl(value); 531159609Sgshapiro cpl ^= 1; 53238032Speter } 53338032Speter diff %= (uint32_t)cycle; 53438032Speter if (diff) { 535168515Sgshapiro if (cpl) 53638032Speter diff = (uint32_t)cycle - diff; 537168515Sgshapiro if (neg) 53890792Sgshapiro diff = ~diff + 1; 53964562Sgshapiro pivot += uint32_2cpl_to_int32(diff); 54038032Speter } 54138032Speter } 54238032Speter return pivot; 54338032Speter} 54490792Sgshapiro 54590792Sgshapiro/*--------------------------------------------------------------------- 54690792Sgshapiro * Note to the casual reader 54738032Speter * 54838032Speter * In the next two functions you will find (or would have found...) 54938032Speter * the expression 55090792Sgshapiro * 55138032Speter * res.Q_s -= 0x80000000; 55238032Speter * 55377349Sgshapiro * There was some ruckus about a possible programming error due to 55438032Speter * integer overflow and sign propagation. 55538032Speter * 55638032Speter * This assumption is based on a lack of understanding of the C 55790792Sgshapiro * standard. (Though this is admittedly not one of the most 'natural' 55890792Sgshapiro * aspects of the 'C' language and easily to get wrong.) 55938032Speter * 56038032Speter * see 56138032Speter * http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf 56238032Speter * "ISO/IEC 9899:201x Committee Draft ��� April 12, 2011" 56338032Speter * 6.4.4.1 Integer constants, clause 5 56490792Sgshapiro * 56590792Sgshapiro * why there is no sign extension/overflow problem here. 56638032Speter * 56738032Speter * But to ease the minds of the doubtful, I added back the 'u' qualifiers 56838032Speter * that somehow got lost over the last years. 56938032Speter */ 57090792Sgshapiro 57190792Sgshapiro 57290792Sgshapiro/* 57390792Sgshapiro *--------------------------------------------------------------------- 57490792Sgshapiro * Convert a timestamp in NTP scale to a 64bit seconds value in the UN*X 57538032Speter * scale with proper epoch unfolding around a given pivot or the current 57638032Speter * system time. This function happily accepts negative pivot values as 57738032Speter * timestamps befor 1970-01-01, so be aware of possible trouble on 57864562Sgshapiro * platforms with 32bit 'time_t'! 57938032Speter * 58064562Sgshapiro * This is also a periodic extension, but since the cycle is 2^32 and 581168515Sgshapiro * the shift is 2^31, we can do some *very* fast math without explicit 58264562Sgshapiro * divisions. 58338032Speter *--------------------------------------------------------------------- 58438032Speter */ 58538032Spetervint64 58664562Sgshapirontpcal_ntp_to_time( 58764562Sgshapiro uint32_t ntp, 58838032Speter const time_t * pivot 58938032Speter ) 59038032Speter{ 59190792Sgshapiro vint64 res; 59264562Sgshapiro 59364562Sgshapiro# if defined(HAVE_INT64) 59464562Sgshapiro 59538032Speter res.q_s = (pivot != NULL) 59638032Speter ? *pivot 59738032Speter : now(); 59838032Speter res.Q_s -= 0x80000000u; /* unshift of half range */ 59938032Speter ntp -= (uint32_t)JAN_1970; /* warp into UN*X domain */ 60038032Speter ntp -= res.D_s.lo; /* cycle difference */ 60138032Speter res.Q_s += (uint64_t)ntp; /* get expanded time */ 60290792Sgshapiro 60390792Sgshapiro# else /* no 64bit scalars */ 60438032Speter 60538032Speter time_t tmp; 60638032Speter 60738032Speter tmp = (pivot != NULL) 60838032Speter ? *pivot 60990792Sgshapiro : now(); 61090792Sgshapiro res = time_to_vint64(&tmp); 61138032Speter M_SUB(res.D_s.hi, res.D_s.lo, 0, 0x80000000u); 61290792Sgshapiro ntp -= (uint32_t)JAN_1970; /* warp into UN*X domain */ 61364562Sgshapiro ntp -= res.D_s.lo; /* cycle difference */ 61490792Sgshapiro M_ADD(res.D_s.hi, res.D_s.lo, 0, ntp); 61590792Sgshapiro 61690792Sgshapiro# endif /* no 64bit scalars */ 61790792Sgshapiro 61890792Sgshapiro return res; 61990792Sgshapiro} 62090792Sgshapiro 62190792Sgshapiro/* 62238032Speter *--------------------------------------------------------------------- 62338032Speter * Convert a timestamp in NTP scale to a 64bit seconds value in the NTP 62490792Sgshapiro * scale with proper epoch unfolding around a given pivot or the current 62590792Sgshapiro * system time. 62690792Sgshapiro * 62738032Speter * Note: The pivot must be given in the UN*X time domain! 62890792Sgshapiro * 62990792Sgshapiro * This is also a periodic extension, but since the cycle is 2^32 and 63090792Sgshapiro * the shift is 2^31, we can do some *very* fast math without explicit 63190792Sgshapiro * divisions. 63290792Sgshapiro *--------------------------------------------------------------------- 63390792Sgshapiro */ 63490792Sgshapirovint64 63590792Sgshapirontpcal_ntp_to_ntp( 63690792Sgshapiro uint32_t ntp, 63790792Sgshapiro const time_t *pivot 63890792Sgshapiro ) 63990792Sgshapiro{ 64038032Speter vint64 res; 64138032Speter 64238032Speter# if defined(HAVE_INT64) 64338032Speter 64438032Speter res.q_s = (pivot) 64538032Speter ? *pivot 64642575Speter : now(); 64742575Speter res.Q_s -= 0x80000000u; /* unshift of half range */ 64838032Speter res.Q_s += (uint32_t)JAN_1970; /* warp into NTP domain */ 64990792Sgshapiro ntp -= res.D_s.lo; /* cycle difference */ 65038032Speter res.Q_s += (uint64_t)ntp; /* get expanded time */ 65138032Speter 65238032Speter# else /* no 64bit scalars */ 65338032Speter 65438032Speter time_t tmp; 65590792Sgshapiro 65638032Speter tmp = (pivot) 65738032Speter ? *pivot 65890792Sgshapiro : now(); 65990792Sgshapiro res = time_to_vint64(&tmp); 66090792Sgshapiro M_SUB(res.D_s.hi, res.D_s.lo, 0, 0x80000000u); 66164562Sgshapiro M_ADD(res.D_s.hi, res.D_s.lo, 0, (uint32_t)JAN_1970);/*into NTP */ 66238032Speter ntp -= res.D_s.lo; /* cycle difference */ 66338032Speter M_ADD(res.D_s.hi, res.D_s.lo, 0, ntp); 66438032Speter 665157001Sgshapiro# endif /* no 64bit scalars */ 66638032Speter 66790792Sgshapiro return res; 66838032Speter} 66938032Speter 67095154Sgshapiro 67195154Sgshapiro/* 67238032Speter * ==================================================================== 67338032Speter * 67438032Speter * Splitting values to composite entities 67538032Speter * 67638032Speter * ==================================================================== 67738032Speter */ 67838032Speter 67964562Sgshapiro/* 68038032Speter *--------------------------------------------------------------------- 68138032Speter * Split a 64bit seconds value into elapsed days in 'res.hi' and 68238032Speter * elapsed seconds since midnight in 'res.lo' using explicit floor 68338032Speter * division. This function happily accepts negative time values as 68438032Speter * timestamps before the respective epoch start. 68538032Speter *--------------------------------------------------------------------- 68664562Sgshapiro */ 68764562Sgshapirontpcal_split 68864562Sgshapirontpcal_daysplit( 68964562Sgshapiro const vint64 *ts 69064562Sgshapiro ) 69164562Sgshapiro{ 69264562Sgshapiro ntpcal_split res; 69364562Sgshapiro uint32_t Q; 69438032Speter 69538032Speter# if defined(HAVE_INT64) 69638032Speter 69738032Speter /* Manual floor division by SECSPERDAY. This uses the one's 69838032Speter * complement trick, too, but without an extra flag value: The 69990792Sgshapiro * flag would be 64bit, and that's a bit of overkill on a 32bit 70038032Speter * target that has to use a register pair for a 64bit number. 70138032Speter */ 70290792Sgshapiro if (ts->q_s < 0) 70338032Speter Q = ~(uint32_t)(~ts->Q_s / SECSPERDAY); 70438032Speter else 705168515Sgshapiro Q = (uint32_t)(ts->Q_s / SECSPERDAY); 70638032Speter 70738032Speter# else 70890792Sgshapiro 70938032Speter uint32_t ah, al, sflag, A; 71038032Speter 71190792Sgshapiro /* get operand into ah/al (either ts or ts' one's complement, 71290792Sgshapiro * for later floor division) 71390792Sgshapiro */ 71438032Speter sflag = int32_sflag(ts->d_s.hi); 71538032Speter ah = sflag ^ ts->D_s.hi; 71638032Speter al = sflag ^ ts->D_s.lo; 717132943Sgshapiro 718132943Sgshapiro /* Since 86400 == 128*675 we can drop the least 7 bits and 71938032Speter * divide by 675 instead of 86400. Then the maximum remainder 72038032Speter * after each devision step is 674, and we need 10 bits for 72138032Speter * that. So in the next step we can shift in 22 bits from the 72238032Speter * numerator. 72338032Speter * 72438032Speter * Therefore we load the accu with the top 13 bits (51..63) in 72590792Sgshapiro * the first shot. We don't have to remember the quotient -- it 72690792Sgshapiro * would be shifted out anyway. 72738032Speter */ 72838032Speter A = ah >> 19; 72938032Speter if (A >= 675) 73038032Speter A = (A % 675u); 73190792Sgshapiro 73290792Sgshapiro /* Now assemble the remainder with bits 29..50 from the 73338032Speter * numerator and divide. This creates the upper ten bits of the 73438032Speter * quotient. (Well, the top 22 bits of a 44bit result. But that 73538032Speter * will be truncated to 32 bits anyway.) 73638032Speter */ 73738032Speter A = (A << 19) | (ah & 0x0007FFFFu); 73838032Speter A = (A << 3) | (al >> 29); 73938032Speter Q = A / 675u; 74038032Speter A = A % 675u; 74190792Sgshapiro 74238032Speter /* Now assemble the remainder with bits 7..28 from the numerator 74338032Speter * and do a final division step. 74464562Sgshapiro */ 74590792Sgshapiro A = (A << 22) | ((al >> 7) & 0x003FFFFFu); 74638032Speter Q = (Q << 22) | (A / 675u); 74764562Sgshapiro 74864562Sgshapiro /* The last 7 bits get simply dropped, as they have no affect on 74964562Sgshapiro * the quotient when dividing by 86400. 75064562Sgshapiro */ 75164562Sgshapiro 75264562Sgshapiro /* apply sign correction and calculate the true floor 75364562Sgshapiro * remainder. 75464562Sgshapiro */ 75564562Sgshapiro Q ^= sflag; 75664562Sgshapiro 75764562Sgshapiro# endif 75864562Sgshapiro 75938032Speter res.hi = uint32_2cpl_to_int32(Q); 76064562Sgshapiro res.lo = ts->D_s.lo - Q * SECSPERDAY; 76164562Sgshapiro 76264562Sgshapiro return res; 76364562Sgshapiro} 76438032Speter 76564562Sgshapiro/* 766168515Sgshapiro *--------------------------------------------------------------------- 76790792Sgshapiro * Split a 32bit seconds value into h/m/s and excessive days. This 76864562Sgshapiro * function happily accepts negative time values as timestamps before 76964562Sgshapiro * midnight. 77064562Sgshapiro *--------------------------------------------------------------------- 77164562Sgshapiro */ 77264562Sgshapirostatic int32_t 77364562Sgshapiropriv_timesplit( 77464562Sgshapiro int32_t split[3], 77564562Sgshapiro int32_t ts 77664562Sgshapiro ) 777168515Sgshapiro{ 77864562Sgshapiro /* Do 3 chained floor divisions by positive constants, using the 779168515Sgshapiro * one's complement trick and factoring out the intermediate XOR 78090792Sgshapiro * ops to reduce the number of operations. 78164562Sgshapiro */ 78264562Sgshapiro uint32_t us, um, uh, ud, sflag; 78338032Speter 78464562Sgshapiro sflag = int32_sflag(ts); 78564562Sgshapiro us = int32_to_uint32_2cpl(ts); 78664562Sgshapiro 78764562Sgshapiro um = (sflag ^ us) / SECSPERMIN; 78890792Sgshapiro uh = um / MINSPERHR; 78964562Sgshapiro ud = uh / HRSPERDAY; 79038032Speter 79164562Sgshapiro um ^= sflag; 79290792Sgshapiro uh ^= sflag; 79371345Sgshapiro ud ^= sflag; 79471345Sgshapiro 79590792Sgshapiro split[0] = (int32_t)(uh - ud * HRSPERDAY ); 79638032Speter split[1] = (int32_t)(um - uh * MINSPERHR ); 79738032Speter split[2] = (int32_t)(us - um * SECSPERMIN); 79838032Speter 79990792Sgshapiro return uint32_2cpl_to_int32(ud); 80090792Sgshapiro} 80164562Sgshapiro 80290792Sgshapiro/* 80338032Speter *--------------------------------------------------------------------- 80438032Speter * Given the number of elapsed days in the calendar era, split this 80538032Speter * number into the number of elapsed years in 'res.hi' and the number 80638032Speter * of elapsed days of that year in 'res.lo'. 80790792Sgshapiro * 80838032Speter * if 'isleapyear' is not NULL, it will receive an integer that is 0 for 80938032Speter * regular years and a non-zero value for leap years. 81042575Speter *--------------------------------------------------------------------- 81138032Speter */ 81238032Speterntpcal_split 81338032Speterntpcal_split_eradays( 81438032Speter int32_t days, 81538032Speter int *isleapyear 81638032Speter ) 81738032Speter{ 81838032Speter /* Use the fast cyclesplit algorithm here, to calculate the 81990792Sgshapiro * centuries and years in a century with one division each. This 82090792Sgshapiro * reduces the number of division operations to two, but is 82138032Speter * susceptible to internal range overflow. We make sure the 82290792Sgshapiro * input operands are in the safe range; this still gives us 82390792Sgshapiro * approx +/-2.9 million years. 82490792Sgshapiro */ 82538032Speter ntpcal_split res; 82638032Speter int32_t n100, n001; /* calendar year cycles */ 82738032Speter uint32_t uday, Q, sflag; 82890792Sgshapiro 82990792Sgshapiro /* split off centuries first */ 83038032Speter sflag = int32_sflag(days); 83138032Speter uday = uint32_saturate(int32_to_uint32_2cpl(days), sflag); 83238032Speter uday = (4u * uday) | 3u; 83338032Speter Q = sflag ^ ((sflag ^ uday) / GREGORIAN_CYCLE_DAYS); 83490792Sgshapiro uday = uday - Q * GREGORIAN_CYCLE_DAYS; 83590792Sgshapiro n100 = uint32_2cpl_to_int32(Q); 83690792Sgshapiro 83764562Sgshapiro /* Split off years in century -- days >= 0 here, and we're far 83890792Sgshapiro * away from integer overflow trouble now. */ 83938032Speter uday |= 3; 84038032Speter n001 = uday / GREGORIAN_NORMAL_LEAP_CYCLE_DAYS; 841132943Sgshapiro uday = uday % GREGORIAN_NORMAL_LEAP_CYCLE_DAYS; 84290792Sgshapiro 84390792Sgshapiro /* Assemble the year and day in year */ 84438032Speter res.hi = n100 * 100 + n001; 84538032Speter res.lo = uday / 4u; 84638032Speter 84738032Speter /* Eventually set the leap year flag. Note: 0 <= n001 <= 99 and 84890792Sgshapiro * Q is still the two's complement representation of the 84938032Speter * centuries: The modulo 4 ops can be done with masking here. 85038032Speter * We also shift the year and the century by one, so the tests 85138032Speter * can be done against zero instead of 3. 85238032Speter */ 85338032Speter if (isleapyear) 85438032Speter *isleapyear = !((n001+1) & 3) 855110560Sgshapiro && ((n001 != 99) || !((Q+1) & 3)); 856110560Sgshapiro 857110560Sgshapiro return res; 858110560Sgshapiro} 85938032Speter 86038032Speter/* 86138032Speter *--------------------------------------------------------------------- 86238032Speter * Given a number of elapsed days in a year and a leap year indicator, 86338032Speter * split the number of elapsed days into the number of elapsed months in 86490792Sgshapiro * 'res.hi' and the number of elapsed days of that month in 'res.lo'. 86538032Speter * 86638032Speter * This function will fail and return {-1,-1} if the number of elapsed 86738032Speter * days is not in the valid range! 86864562Sgshapiro *--------------------------------------------------------------------- 86964562Sgshapiro */ 87090792Sgshapirontpcal_split 87164562Sgshapirontpcal_split_yeardays( 87264562Sgshapiro int32_t eyd, 87338032Speter int isleapyear 87490792Sgshapiro ) 87590792Sgshapiro{ 87690792Sgshapiro ntpcal_split res; 877168515Sgshapiro const uint16_t *lt; /* month length table */ 87890792Sgshapiro 87990792Sgshapiro /* check leap year flag and select proper table */ 88090792Sgshapiro lt = real_month_table[(isleapyear != 0)]; 88138032Speter if (0 <= eyd && eyd < lt[12]) { 88238032Speter /* get zero-based month by approximation & correction step */ 88338032Speter res.hi = eyd >> 5; /* approx month; might be 1 too low */ 88438032Speter if (lt[res.hi + 1] <= eyd) /* fixup approximative month value */ 88538032Speter res.hi += 1; 88638032Speter res.lo = eyd - lt[res.hi]; 88764562Sgshapiro } else { 88864562Sgshapiro res.lo = res.hi = -1; 88964562Sgshapiro } 89064562Sgshapiro 89164562Sgshapiro return res; 89238032Speter} 89390792Sgshapiro 89490792Sgshapiro/* 89538032Speter *--------------------------------------------------------------------- 89638032Speter * Convert a RD into the date part of a 'struct calendar'. 89738032Speter *--------------------------------------------------------------------- 89890792Sgshapiro */ 89938032Speterint 90090792Sgshapirontpcal_rd_to_date( 90190792Sgshapiro struct calendar *jd, 90290792Sgshapiro int32_t rd 90338032Speter ) 90438032Speter{ 90538032Speter ntpcal_split split; 90638032Speter int leapy; 90738032Speter u_int ymask; 90838032Speter 90990792Sgshapiro /* Get day-of-week first. Since rd is signed, the remainder can 91038032Speter * be in the range [-6..+6], but the assignment to an unsigned 91190792Sgshapiro * variable maps the negative values to positive values >=7. 91238032Speter * This makes the sign correction look strange, but adding 7 91390792Sgshapiro * causes the needed wrap-around into the desired value range of 91438032Speter * zero to six, both inclusive. 91538032Speter */ 91638032Speter jd->weekday = rd % DAYSPERWEEK; 91738032Speter if (jd->weekday >= DAYSPERWEEK) /* weekday is unsigned! */ 91838032Speter jd->weekday += DAYSPERWEEK; 91938032Speter 92038032Speter split = ntpcal_split_eradays(rd - 1, &leapy); 92138032Speter /* Get year and day-of-year, with overflow check. If any of the 92238032Speter * upper 16 bits is set after shifting to unity-based years, we 92338032Speter * will have an overflow when converting to an unsigned 16bit 92490792Sgshapiro * year. Shifting to the right is OK here, since it does not 92590792Sgshapiro * matter if the shift is logic or arithmetic. 92638032Speter */ 92738032Speter split.hi += 1; 92838032Speter ymask = 0u - ((split.hi >> 16) == 0); 92990792Sgshapiro jd->year = (uint16_t)(split.hi & ymask); 93038032Speter jd->yearday = (uint16_t)split.lo + 1; 93138032Speter 93238032Speter /* convert to month and mday */ 93390792Sgshapiro split = ntpcal_split_yeardays(split.lo, leapy); 93438032Speter jd->month = (uint8_t)split.hi + 1; 93538032Speter jd->monthday = (uint8_t)split.lo + 1; 93638032Speter 93738032Speter return ymask ? leapy : -1; 93838032Speter} 93938032Speter 940120256Sgshapiro/* 941120256Sgshapiro *--------------------------------------------------------------------- 942120256Sgshapiro * Convert a RD into the date part of a 'struct tm'. 94390792Sgshapiro *--------------------------------------------------------------------- 94490792Sgshapiro */ 94538032Speterint 94638032Speterntpcal_rd_to_tm( 94738032Speter struct tm *utm, 94838032Speter int32_t rd 949120256Sgshapiro ) 950120256Sgshapiro{ 951120256Sgshapiro ntpcal_split split; 95290792Sgshapiro int leapy; 95390792Sgshapiro 95438032Speter /* get day-of-week first */ 95538032Speter utm->tm_wday = rd % DAYSPERWEEK; 95638032Speter if (utm->tm_wday < 0) 95790792Sgshapiro utm->tm_wday += DAYSPERWEEK; 95890792Sgshapiro 95990792Sgshapiro /* get year and day-of-year */ 96090792Sgshapiro split = ntpcal_split_eradays(rd - 1, &leapy); 96190792Sgshapiro utm->tm_year = split.hi - 1899; 96290792Sgshapiro utm->tm_yday = split.lo; /* 0-based */ 96390792Sgshapiro 96490792Sgshapiro /* convert to month and mday */ 96590792Sgshapiro split = ntpcal_split_yeardays(split.lo, leapy); 96690792Sgshapiro utm->tm_mon = split.hi; /* 0-based */ 96790792Sgshapiro utm->tm_mday = split.lo + 1; /* 1-based */ 96890792Sgshapiro 96990792Sgshapiro return leapy; 97090792Sgshapiro} 97190792Sgshapiro 97290792Sgshapiro/* 97390792Sgshapiro *--------------------------------------------------------------------- 97490792Sgshapiro * Take a value of seconds since midnight and split it into hhmmss in a 97538032Speter * 'struct calendar'. 97664562Sgshapiro *--------------------------------------------------------------------- 97764562Sgshapiro */ 97864562Sgshapiroint32_t 97964562Sgshapirontpcal_daysec_to_date( 98064562Sgshapiro struct calendar *jd, 98190792Sgshapiro int32_t sec 98264562Sgshapiro ) 98364562Sgshapiro{ 98464562Sgshapiro int32_t days; 98564562Sgshapiro int ts[3]; 98664562Sgshapiro 98764562Sgshapiro days = priv_timesplit(ts, sec); 98864562Sgshapiro jd->hour = (uint8_t)ts[0]; 98964562Sgshapiro jd->minute = (uint8_t)ts[1]; 99064562Sgshapiro jd->second = (uint8_t)ts[2]; 99190792Sgshapiro 99264562Sgshapiro return days; 99338032Speter} 99490792Sgshapiro 99590792Sgshapiro/* 99690792Sgshapiro *--------------------------------------------------------------------- 99790792Sgshapiro * Take a value of seconds since midnight and split it into hhmmss in a 99890792Sgshapiro * 'struct tm'. 99990792Sgshapiro *--------------------------------------------------------------------- 100064562Sgshapiro */ 100138032Speterint32_t 100238032Speterntpcal_daysec_to_tm( 100390792Sgshapiro struct tm *utm, 100490792Sgshapiro int32_t sec 100590792Sgshapiro ) 100690792Sgshapiro{ 100790792Sgshapiro int32_t days; 100890792Sgshapiro int32_t ts[3]; 100990792Sgshapiro 101090792Sgshapiro days = priv_timesplit(ts, sec); 101190792Sgshapiro utm->tm_hour = ts[0]; 101290792Sgshapiro utm->tm_min = ts[1]; 101390792Sgshapiro utm->tm_sec = ts[2]; 101490792Sgshapiro 101590792Sgshapiro return days; 101690792Sgshapiro} 101790792Sgshapiro 101890792Sgshapiro/* 101990792Sgshapiro *--------------------------------------------------------------------- 1020168515Sgshapiro * take a split representation for day/second-of-day and day offset 102138032Speter * and convert it to a 'struct calendar'. The seconds will be normalised 102290792Sgshapiro * into the range of a day, and the day will be adjusted accordingly. 102338032Speter * 102438032Speter * returns >0 if the result is in a leap year, 0 if in a regular 102538032Speter * year and <0 if the result did not fit into the calendar struct. 102638032Speter *--------------------------------------------------------------------- 102790792Sgshapiro */ 1028168515Sgshapiroint 102938032Speterntpcal_daysplit_to_date( 103090792Sgshapiro struct calendar *jd, 103138032Speter const ntpcal_split *ds, 103238032Speter int32_t dof 103338032Speter ) 103438032Speter{ 103590792Sgshapiro dof += ntpcal_daysec_to_date(jd, ds->lo); 1036168515Sgshapiro return ntpcal_rd_to_date(jd, ds->hi + dof); 103738032Speter} 103890792Sgshapiro 103938032Speter/* 104038032Speter *--------------------------------------------------------------------- 104138032Speter * take a split representation for day/second-of-day and day offset 104238032Speter * and convert it to a 'struct tm'. The seconds will be normalised 104390792Sgshapiro * into the range of a day, and the day will be adjusted accordingly. 104490792Sgshapiro * 104590792Sgshapiro * returns 1 if the result is in a leap year and zero if in a regular 104690792Sgshapiro * year. 104790792Sgshapiro *--------------------------------------------------------------------- 104890792Sgshapiro */ 104990792Sgshapiroint 1050168515Sgshapirontpcal_daysplit_to_tm( 105190792Sgshapiro struct tm *utm, 105290792Sgshapiro const ntpcal_split *ds , 105390792Sgshapiro int32_t dof 105490792Sgshapiro ) 105590792Sgshapiro{ 105690792Sgshapiro dof += ntpcal_daysec_to_tm(utm, ds->lo); 105790792Sgshapiro 105890792Sgshapiro return ntpcal_rd_to_tm(utm, ds->hi + dof); 105990792Sgshapiro} 106090792Sgshapiro 106190792Sgshapiro/* 106290792Sgshapiro *--------------------------------------------------------------------- 106390792Sgshapiro * Take a UN*X time and convert to a calendar structure. 106490792Sgshapiro *--------------------------------------------------------------------- 106590792Sgshapiro */ 106690792Sgshapiroint 106790792Sgshapirontpcal_time_to_date( 106890792Sgshapiro struct calendar *jd, 106990792Sgshapiro const vint64 *ts 107090792Sgshapiro ) 107190792Sgshapiro{ 107238032Speter ntpcal_split ds; 107364562Sgshapiro 107438032Speter ds = ntpcal_daysplit(ts); 107598841Sgshapiro ds.hi += ntpcal_daysec_to_date(jd, ds.lo); 107698841Sgshapiro ds.hi += DAY_UNIX_STARTS; 107798841Sgshapiro 107898841Sgshapiro return ntpcal_rd_to_date(jd, ds.hi); 107998841Sgshapiro} 108064562Sgshapiro 108164562Sgshapiro 108264562Sgshapiro/* 108364562Sgshapiro * ==================================================================== 108438032Speter * 108538032Speter * merging composite entities 108638032Speter * 108738032Speter * ==================================================================== 108838032Speter */ 108990792Sgshapiro 109090792Sgshapiro/* 109138032Speter *--------------------------------------------------------------------- 109238032Speter * Merge a number of days and a number of seconds into seconds, 109338032Speter * expressed in 64 bits to avoid overflow. 109438032Speter *--------------------------------------------------------------------- 109538032Speter */ 109690792Sgshapirovint64 109790792Sgshapirontpcal_dayjoin( 109890792Sgshapiro int32_t days, 109990792Sgshapiro int32_t secs 110038032Speter ) 110138032Speter{ 110238032Speter vint64 res; 110338032Speter 110490792Sgshapiro# if defined(HAVE_INT64) 110590792Sgshapiro 110638032Speter res.q_s = days; 110738032Speter res.q_s *= SECSPERDAY; 110838032Speter res.q_s += secs; 110990792Sgshapiro 111090792Sgshapiro# else 111138032Speter 111238032Speter uint32_t p1, p2; 111338032Speter int isneg; 111490792Sgshapiro 111538032Speter /* 111638032Speter * res = days *86400 + secs, using manual 16/32 bit 111738032Speter * multiplications and shifts. 111838032Speter */ 111938032Speter isneg = (days < 0); 112038032Speter if (isneg) 112164562Sgshapiro days = -days; 112290792Sgshapiro 112390792Sgshapiro /* assemble days * 675 */ 112490792Sgshapiro res.D_s.lo = (days & 0xFFFF) * 675u; 112564562Sgshapiro res.D_s.hi = 0; 112638032Speter p1 = (days >> 16) * 675u; 112738032Speter p2 = p1 >> 16; 112838032Speter p1 = p1 << 16; 112990792Sgshapiro M_ADD(res.D_s.hi, res.D_s.lo, p2, p1); 113064562Sgshapiro 113164562Sgshapiro /* mul by 128, using shift */ 113264562Sgshapiro res.D_s.hi = (res.D_s.hi << 7) | (res.D_s.lo >> 25); 113390792Sgshapiro res.D_s.lo = (res.D_s.lo << 7); 113490792Sgshapiro 113590792Sgshapiro /* fix sign */ 113690792Sgshapiro if (isneg) 113764562Sgshapiro M_NEG(res.D_s.hi, res.D_s.lo); 113890792Sgshapiro 113990792Sgshapiro /* properly add seconds */ 114090792Sgshapiro p2 = 0; 114190792Sgshapiro if (secs < 0) { 114238032Speter p1 = (uint32_t)-secs; 114338032Speter M_NEG(p2, p1); 114438032Speter } else { 114538032Speter p1 = (uint32_t)secs; 114638032Speter } 114738032Speter M_ADD(res.D_s.hi, res.D_s.lo, p2, p1); 114890792Sgshapiro 114990792Sgshapiro# endif 115038032Speter 115138032Speter return res; 115238032Speter} 115338032Speter 115438032Speter/* 115538032Speter *--------------------------------------------------------------------- 115638032Speter * get leap years since epoch in elapsed years 115738032Speter *--------------------------------------------------------------------- 115890792Sgshapiro */ 115938032Speterint32_t 116038032Speterntpcal_leapyears_in_years( 116138032Speter int32_t years 116238032Speter ) 116390792Sgshapiro{ 116438032Speter /* We use the in-out-in algorithm here, using the one's 116538032Speter * complement division trick for negative numbers. The chained 116638032Speter * division sequence by 4/25/4 gives the compiler the chance to 116790792Sgshapiro * get away with only one true division and doing shifts otherwise. 116838032Speter */ 116938032Speter 117064562Sgshapiro uint32_t sflag, sum, uyear; 117138032Speter 117290792Sgshapiro sflag = int32_sflag(years); 117338032Speter uyear = int32_to_uint32_2cpl(years); 117464562Sgshapiro uyear ^= sflag; 117538032Speter 117664562Sgshapiro sum = (uyear /= 4u); /* 4yr rule --> IN */ 117738032Speter sum -= (uyear /= 25u); /* 100yr rule --> OUT */ 117838032Speter sum += (uyear /= 4u); /* 400yr rule --> IN */ 117964562Sgshapiro 118064562Sgshapiro /* Thanks to the alternation of IN/OUT/IN we can do the sum 118138032Speter * directly and have a single one's complement operation 118238032Speter * here. (Only if the years are negative, of course.) Otherwise 118364562Sgshapiro * the one's complement would have to be done when 118438032Speter * adding/subtracting the terms. 118564562Sgshapiro */ 118638032Speter return uint32_2cpl_to_int32(sflag ^ sum); 118738032Speter} 118890792Sgshapiro 118990792Sgshapiro/* 119038032Speter *--------------------------------------------------------------------- 119138032Speter * Convert elapsed years in Era into elapsed days in Era. 119238032Speter *--------------------------------------------------------------------- 119338032Speter */ 119490792Sgshapiroint32_t 119590792Sgshapirontpcal_days_in_years( 119690792Sgshapiro int32_t years 119764562Sgshapiro ) 119890792Sgshapiro{ 119990792Sgshapiro return years * DAYSPERYEAR + ntpcal_leapyears_in_years(years); 120064562Sgshapiro} 120190792Sgshapiro 120290792Sgshapiro/* 120364562Sgshapiro *--------------------------------------------------------------------- 120498841Sgshapiro * Convert a number of elapsed month in a year into elapsed days in year. 120598841Sgshapiro * 120698841Sgshapiro * The month will be normalized, and 'res.hi' will contain the 120798841Sgshapiro * excessive years that must be considered when converting the years, 120864562Sgshapiro * while 'res.lo' will contain the number of elapsed days since start 120990792Sgshapiro * of the year. 121064562Sgshapiro * 121190792Sgshapiro * This code uses the shifted-month-approach to convert month to days, 121298841Sgshapiro * because then there is no need to have explicit leap year 121398841Sgshapiro * information. The slight disadvantage is that for most month values 121498841Sgshapiro * the result is a negative value, and the year excess is one; the 121598841Sgshapiro * conversion is then simply based on the start of the following year. 121698841Sgshapiro *--------------------------------------------------------------------- 121764562Sgshapiro */ 121864562Sgshapirontpcal_split 121938032Speterntpcal_days_in_months( 122038032Speter int32_t m 122138032Speter ) 122238032Speter{ 122338032Speter ntpcal_split res; 122438032Speter 122538032Speter /* Add ten months and correct if needed. (It likely is...) */ 122638032Speter res.lo = m + 10; 122764562Sgshapiro res.hi = (res.lo >= 12); 122890792Sgshapiro if (res.hi) 122964562Sgshapiro res.lo -= 12; 123090792Sgshapiro 123190792Sgshapiro /* if still out of range, normalise by floor division ... */ 123290792Sgshapiro if (res.lo < 0 || res.lo >= 12) { 123390792Sgshapiro uint32_t mu, Q, sflag; 123490792Sgshapiro sflag = int32_sflag(res.lo); 123590792Sgshapiro mu = int32_to_uint32_2cpl(res.lo); 123638032Speter Q = sflag ^ ((sflag ^ mu) / 12u); 123790792Sgshapiro res.hi += uint32_2cpl_to_int32(Q); 123890792Sgshapiro res.lo = mu - Q * 12u; 123990792Sgshapiro } 124090792Sgshapiro 124190792Sgshapiro /* get cummulated days in year with unshift */ 124290792Sgshapiro res.lo = shift_month_table[res.lo] - 306; 124390792Sgshapiro 1244168515Sgshapiro return res; 124590792Sgshapiro} 1246168515Sgshapiro 124790792Sgshapiro/* 1248168515Sgshapiro *--------------------------------------------------------------------- 124990792Sgshapiro * Convert ELAPSED years/months/days of gregorian calendar to elapsed 125090792Sgshapiro * days in Gregorian epoch. 125190792Sgshapiro * 125290792Sgshapiro * If you want to convert years and days-of-year, just give a month of 125390792Sgshapiro * zero. 125490792Sgshapiro *--------------------------------------------------------------------- 125590792Sgshapiro */ 125677349Sgshapiroint32_t 125790792Sgshapirontpcal_edate_to_eradays( 125877349Sgshapiro int32_t years, 125977349Sgshapiro int32_t mons, 126077349Sgshapiro int32_t mdays 126177349Sgshapiro ) 126277349Sgshapiro{ 126377349Sgshapiro ntpcal_split tmp; 126477349Sgshapiro int32_t res; 126577349Sgshapiro 126677349Sgshapiro if (mons) { 126777349Sgshapiro tmp = ntpcal_days_in_months(mons); 126877349Sgshapiro res = ntpcal_days_in_years(years + tmp.hi) + tmp.lo; 126977349Sgshapiro } else 127077349Sgshapiro res = ntpcal_days_in_years(years); 127177349Sgshapiro res += mdays; 127290792Sgshapiro 127377349Sgshapiro return res; 127477349Sgshapiro} 127577349Sgshapiro 127677349Sgshapiro/* 127790792Sgshapiro *--------------------------------------------------------------------- 127877349Sgshapiro * Convert ELAPSED years/months/days of gregorian calendar to elapsed 127977349Sgshapiro * days in year. 128077349Sgshapiro * 128190792Sgshapiro * Note: This will give the true difference to the start of the given 128290792Sgshapiro * year, even if months & days are off-scale. 128377349Sgshapiro *--------------------------------------------------------------------- 128477349Sgshapiro */ 128577349Sgshapiroint32_t 128677349Sgshapirontpcal_edate_to_yeardays( 128777349Sgshapiro int32_t years, 128877349Sgshapiro int32_t mons, 128977349Sgshapiro int32_t mdays 129090792Sgshapiro ) 129177349Sgshapiro{ 129277349Sgshapiro ntpcal_split tmp; 129377349Sgshapiro 129490792Sgshapiro if (0 <= mons && mons < 12) { 129577349Sgshapiro years += 1; 129677349Sgshapiro mdays += real_month_table[is_leapyear(years)][mons]; 129777349Sgshapiro } else { 129890792Sgshapiro tmp = ntpcal_days_in_months(mons); 129990792Sgshapiro mdays += tmp.lo 130077349Sgshapiro + ntpcal_days_in_years(years + tmp.hi) 130177349Sgshapiro - ntpcal_days_in_years(years); 130277349Sgshapiro } 130390792Sgshapiro 1304132943Sgshapiro return mdays; 1305132943Sgshapiro} 130690792Sgshapiro 130790792Sgshapiro/* 130890792Sgshapiro *--------------------------------------------------------------------- 130990792Sgshapiro * Convert elapsed days and the hour/minute/second information into 131090792Sgshapiro * total seconds. 131190792Sgshapiro * 131290792Sgshapiro * If 'isvalid' is not NULL, do a range check on the time specification 131390792Sgshapiro * and tell if the time input is in the normal range, permitting for a 131490792Sgshapiro * single leapsecond. 131590792Sgshapiro *--------------------------------------------------------------------- 131690792Sgshapiro */ 131790792Sgshapiroint32_t 131890792Sgshapirontpcal_etime_to_seconds( 131990792Sgshapiro int32_t hours, 132090792Sgshapiro int32_t minutes, 132190792Sgshapiro int32_t seconds 132290792Sgshapiro ) 132390792Sgshapiro{ 132490792Sgshapiro int32_t res; 132577349Sgshapiro 132690792Sgshapiro res = (hours * MINSPERHR + minutes) * SECSPERMIN + seconds; 132790792Sgshapiro 132890792Sgshapiro return res; 132977349Sgshapiro} 133038032Speter 133138032Speter/* 133238032Speter *--------------------------------------------------------------------- 133338032Speter * Convert the date part of a 'struct tm' (that is, year, month, 1334157001Sgshapiro * day-of-month) into the RD of that day. 133538032Speter *--------------------------------------------------------------------- 1336157001Sgshapiro */ 133738032Speterint32_t 133838032Speterntpcal_tm_to_rd( 133990792Sgshapiro const struct tm *utm 134090792Sgshapiro ) 134190792Sgshapiro{ 134290792Sgshapiro return ntpcal_edate_to_eradays(utm->tm_year + 1899, 134390792Sgshapiro utm->tm_mon, 134490792Sgshapiro utm->tm_mday - 1) + 1; 134590792Sgshapiro} 134690792Sgshapiro 134790792Sgshapiro/* 134838032Speter *--------------------------------------------------------------------- 134938032Speter * Convert the date part of a 'struct calendar' (that is, year, month, 135038032Speter * day-of-month) into the RD of that day. 135190792Sgshapiro *--------------------------------------------------------------------- 135238032Speter */ 135390792Sgshapiroint32_t 135490792Sgshapirontpcal_date_to_rd( 135590792Sgshapiro const struct calendar *jd 135690792Sgshapiro ) 135790792Sgshapiro{ 135890792Sgshapiro return ntpcal_edate_to_eradays((int32_t)jd->year - 1, 135990792Sgshapiro (int32_t)jd->month - 1, 136090792Sgshapiro (int32_t)jd->monthday - 1) + 1; 136190792Sgshapiro} 136290792Sgshapiro 136338032Speter/* 136490792Sgshapiro *--------------------------------------------------------------------- 136564562Sgshapiro * convert a year number to rata die of year start 136690792Sgshapiro *--------------------------------------------------------------------- 136790792Sgshapiro */ 136890792Sgshapiroint32_t 136990792Sgshapirontpcal_year_to_ystart( 137090792Sgshapiro int32_t year 137190792Sgshapiro ) 137238032Speter{ 137338032Speter return ntpcal_days_in_years(year - 1) + 1; 137464562Sgshapiro} 137564562Sgshapiro 137664562Sgshapiro/* 137764562Sgshapiro *--------------------------------------------------------------------- 137864562Sgshapiro * For a given RD, get the RD of the associated year start, 137938032Speter * that is, the RD of the last January,1st on or before that day. 138038032Speter *--------------------------------------------------------------------- 138138032Speter */ 138238032Speterint32_t 138364562Sgshapirontpcal_rd_to_ystart( 138490792Sgshapiro int32_t rd 138538032Speter ) 138638032Speter{ 138790792Sgshapiro /* 138890792Sgshapiro * Rather simple exercise: split the day number into elapsed 138938032Speter * years and elapsed days, then remove the elapsed days from the 139038032Speter * input value. Nice'n sweet... 1391168515Sgshapiro */ 139273188Sgshapiro return rd - ntpcal_split_eradays(rd - 1, NULL).lo; 139373188Sgshapiro} 139438032Speter 139538032Speter/* 139690792Sgshapiro *--------------------------------------------------------------------- 139738032Speter * For a given RD, get the RD of the associated month start. 139838032Speter *--------------------------------------------------------------------- 139990792Sgshapiro */ 140090792Sgshapiroint32_t 1401110560Sgshapirontpcal_rd_to_mstart( 1402110560Sgshapiro int32_t rd 140390792Sgshapiro ) 140490792Sgshapiro{ 140590792Sgshapiro ntpcal_split split; 1406168515Sgshapiro int leaps; 1407110560Sgshapiro 140890792Sgshapiro split = ntpcal_split_eradays(rd - 1, &leaps); 140990792Sgshapiro split = ntpcal_split_yeardays(split.lo, leaps); 141038032Speter 141138032Speter return rd - split.lo; 141290792Sgshapiro} 141390792Sgshapiro 1414132943Sgshapiro/* 141590792Sgshapiro *--------------------------------------------------------------------- 1416132943Sgshapiro * take a 'struct calendar' and get the seconds-of-day from it. 141790792Sgshapiro *--------------------------------------------------------------------- 1418132943Sgshapiro */ 141990792Sgshapiroint32_t 1420132943Sgshapirontpcal_date_to_daysec( 142190792Sgshapiro const struct calendar *jd 142238032Speter ) 142338032Speter{ 142438032Speter return ntpcal_etime_to_seconds(jd->hour, jd->minute, 142538032Speter jd->second); 142638032Speter} 142738032Speter 142838032Speter/* 142938032Speter *--------------------------------------------------------------------- 143038032Speter * take a 'struct tm' and get the seconds-of-day from it. 143190792Sgshapiro *--------------------------------------------------------------------- 143290792Sgshapiro */ 143364562Sgshapiroint32_t 143490792Sgshapirontpcal_tm_to_daysec( 143590792Sgshapiro const struct tm *utm 143690792Sgshapiro ) 143790792Sgshapiro{ 143890792Sgshapiro return ntpcal_etime_to_seconds(utm->tm_hour, utm->tm_min, 143990792Sgshapiro utm->tm_sec); 144038032Speter} 144138032Speter 144290792Sgshapiro/* 144390792Sgshapiro *--------------------------------------------------------------------- 144438032Speter * take a 'struct calendar' and convert it to a 'time_t' 144590792Sgshapiro *--------------------------------------------------------------------- 144690792Sgshapiro */ 144738032Spetertime_t 144890792Sgshapirontpcal_date_to_time( 144990792Sgshapiro const struct calendar *jd 145038032Speter ) 145138032Speter{ 145238032Speter vint64 join; 145338032Speter int32_t days, secs; 145438032Speter 145538032Speter days = ntpcal_date_to_rd(jd) - DAY_UNIX_STARTS; 145638032Speter secs = ntpcal_date_to_daysec(jd); 145738032Speter join = ntpcal_dayjoin(days, secs); 145838032Speter 145990792Sgshapiro return vint64_to_time(&join); 146038032Speter} 146138032Speter 146238032Speter 146338032Speter/* 146438032Speter * ==================================================================== 146538032Speter * 146690792Sgshapiro * extended and unchecked variants of caljulian/caltontp 146790792Sgshapiro * 146838032Speter * ==================================================================== 146938032Speter */ 147038032Speterint 147138032Speterntpcal_ntp64_to_date( 147238032Speter struct calendar *jd, 147390792Sgshapiro const vint64 *ntp 147490792Sgshapiro ) 147590792Sgshapiro{ 147638032Speter ntpcal_split ds; 147738032Speter 1478157001Sgshapiro ds = ntpcal_daysplit(ntp); 1479157001Sgshapiro ds.hi += ntpcal_daysec_to_date(jd, ds.lo); 1480157001Sgshapiro 1481157001Sgshapiro return ntpcal_rd_to_date(jd, ds.hi + DAY_NTP_STARTS); 1482157001Sgshapiro} 1483157001Sgshapiro 1484157001Sgshapiroint 1485157001Sgshapirontpcal_ntp_to_date( 1486157001Sgshapiro struct calendar *jd, 1487157001Sgshapiro uint32_t ntp, 148838032Speter const time_t *piv 148990792Sgshapiro ) 149042575Speter{ 149138032Speter vint64 ntp64; 149290792Sgshapiro 149390792Sgshapiro /* 149490792Sgshapiro * Unfold ntp time around current time into NTP domain. Split 149590792Sgshapiro * into days and seconds, shift days into CE domain and 149690792Sgshapiro * process the parts. 149790792Sgshapiro */ 149890792Sgshapiro ntp64 = ntpcal_ntp_to_ntp(ntp, piv); 149990792Sgshapiro return ntpcal_ntp64_to_date(jd, &ntp64); 1500132943Sgshapiro} 1501132943Sgshapiro 1502132943Sgshapiro 1503132943Sgshapirovint64 1504132943Sgshapirontpcal_date_to_ntp64( 150590792Sgshapiro const struct calendar *jd 150690792Sgshapiro ) 150790792Sgshapiro{ 150890792Sgshapiro /* 150990792Sgshapiro * Convert date to NTP. Ignore yearday, use d/m/y only. 151090792Sgshapiro */ 151190792Sgshapiro return ntpcal_dayjoin(ntpcal_date_to_rd(jd) - DAY_NTP_STARTS, 151290792Sgshapiro ntpcal_date_to_daysec(jd)); 151390792Sgshapiro} 151490792Sgshapiro 151590792Sgshapiro 151690792Sgshapirouint32_t 151790792Sgshapirontpcal_date_to_ntp( 151890792Sgshapiro const struct calendar *jd 151990792Sgshapiro ) 152090792Sgshapiro{ 152190792Sgshapiro /* 152290792Sgshapiro * Get lower half of 64-bit NTP timestamp from date/time. 152390792Sgshapiro */ 152490792Sgshapiro return ntpcal_date_to_ntp64(jd).d_s.lo; 152590792Sgshapiro} 152690792Sgshapiro 152790792Sgshapiro 152890792Sgshapiro 152990792Sgshapiro/* 153090792Sgshapiro * ==================================================================== 153190792Sgshapiro * 153290792Sgshapiro * day-of-week calculations 153390792Sgshapiro * 153490792Sgshapiro * ==================================================================== 153590792Sgshapiro */ 153690792Sgshapiro/* 153790792Sgshapiro * Given a RataDie and a day-of-week, calculate a RDN that is reater-than, 153890792Sgshapiro * greater-or equal, closest, less-or-equal or less-than the given RDN 153990792Sgshapiro * and denotes the given day-of-week 154090792Sgshapiro */ 154190792Sgshapiroint32_t 154290792Sgshapirontpcal_weekday_gt( 154390792Sgshapiro int32_t rdn, 154490792Sgshapiro int32_t dow 154590792Sgshapiro ) 154690792Sgshapiro{ 154790792Sgshapiro return ntpcal_periodic_extend(rdn+1, dow, 7); 154890792Sgshapiro} 154990792Sgshapiro 155090792Sgshapiroint32_t 155190792Sgshapirontpcal_weekday_ge( 155290792Sgshapiro int32_t rdn, 155390792Sgshapiro int32_t dow 155490792Sgshapiro ) 155590792Sgshapiro{ 155690792Sgshapiro return ntpcal_periodic_extend(rdn, dow, 7); 155790792Sgshapiro} 155890792Sgshapiro 155990792Sgshapiroint32_t 156090792Sgshapirontpcal_weekday_close( 156190792Sgshapiro int32_t rdn, 156290792Sgshapiro int32_t dow 156390792Sgshapiro ) 156490792Sgshapiro{ 156590792Sgshapiro return ntpcal_periodic_extend(rdn-3, dow, 7); 156690792Sgshapiro} 156790792Sgshapiro 156890792Sgshapiroint32_t 156990792Sgshapirontpcal_weekday_le( 157090792Sgshapiro int32_t rdn, 157190792Sgshapiro int32_t dow 157290792Sgshapiro ) 157390792Sgshapiro{ 157490792Sgshapiro return ntpcal_periodic_extend(rdn, dow, -7); 157590792Sgshapiro} 157690792Sgshapiro 157790792Sgshapiroint32_t 157890792Sgshapirontpcal_weekday_lt( 157990792Sgshapiro int32_t rdn, 158090792Sgshapiro int32_t dow 158190792Sgshapiro ) 158290792Sgshapiro{ 158390792Sgshapiro return ntpcal_periodic_extend(rdn-1, dow, -7); 158490792Sgshapiro} 158590792Sgshapiro 158690792Sgshapiro/* 158790792Sgshapiro * ==================================================================== 158890792Sgshapiro * 158990792Sgshapiro * ISO week-calendar conversions 159090792Sgshapiro * 159190792Sgshapiro * The ISO8601 calendar defines a calendar of years, weeks and weekdays. 159290792Sgshapiro * It is related to the Gregorian calendar, and a ISO year starts at the 159390792Sgshapiro * Monday closest to Jan,1st of the corresponding Gregorian year. A ISO 159490792Sgshapiro * calendar year has always 52 or 53 weeks, and like the Grogrian 159590792Sgshapiro * calendar the ISO8601 calendar repeats itself every 400 years, or 159690792Sgshapiro * 146097 days, or 20871 weeks. 159790792Sgshapiro * 159890792Sgshapiro * While it is possible to write ISO calendar functions based on the 159990792Sgshapiro * Gregorian calendar functions, the following implementation takes a 160090792Sgshapiro * different approach, based directly on years and weeks. 160190792Sgshapiro * 160290792Sgshapiro * Analysis of the tabulated data shows that it is not possible to 160390792Sgshapiro * interpolate from years to weeks over a full 400 year range; cyclic 160490792Sgshapiro * shifts over 400 years do not provide a solution here. But it *is* 160590792Sgshapiro * possible to interpolate over every single century of the 400-year 160690792Sgshapiro * cycle. (The centennial leap year rule seems to be the culprit here.) 160790792Sgshapiro * 160890792Sgshapiro * It can be shown that a conversion from years to weeks can be done 160990792Sgshapiro * using a linear transformation of the form 161090792Sgshapiro * 161190792Sgshapiro * w = floor( y * a + b ) 161290792Sgshapiro * 161390792Sgshapiro * where the slope a must hold to 161490792Sgshapiro * 161590792Sgshapiro * 52.1780821918 <= a < 52.1791044776 161690792Sgshapiro * 161790792Sgshapiro * and b must be chosen according to the selected slope and the number 161890792Sgshapiro * of the century in a 400-year period. 161938032Speter * 162038032Speter * The inverse calculation can also be done in this way. Careful scaling 162138032Speter * provides an unlimited set of integer coefficients a,k,b that enable 162238032Speter * us to write the calulation in the form 162338032Speter * 162438032Speter * w = (y * a + b ) / k 162538032Speter * y = (w * a' + b') / k' 162638032Speter * 162738032Speter * In this implementation the values of k and k' are chosen to be 162838032Speter * smallest possible powers of two, so the division can be implemented 162938032Speter * as shifts if the optimiser chooses to do so. 163038032Speter * 163190792Sgshapiro * ==================================================================== 163290792Sgshapiro */ 163338032Speter 163438032Speter/* 163538032Speter * Given a number of elapsed (ISO-)years since the begin of the 163690792Sgshapiro * christian era, return the number of elapsed weeks corresponding to 163790792Sgshapiro * the number of years. 163838032Speter */ 163990792Sgshapiroint32_t 164090792Sgshapiroisocal_weeks_in_years( 164190792Sgshapiro int32_t years 164290792Sgshapiro ) 164390792Sgshapiro{ 164438032Speter /* 164538032Speter * use: w = (y * 53431 + b[c]) / 1024 as interpolation 164638032Speter */ 164790792Sgshapiro static const uint16_t bctab[4] = { 157, 449, 597, 889 }; 164890792Sgshapiro 164964562Sgshapiro int32_t cs, cw; 165038032Speter uint32_t cc, ci, yu, sflag; 165138032Speter 165290792Sgshapiro sflag = int32_sflag(years); 165338032Speter yu = int32_to_uint32_2cpl(years); 165438032Speter 165538032Speter /* split off centuries, using floor division */ 165690792Sgshapiro cc = sflag ^ ((sflag ^ yu) / 100u); 165738032Speter yu -= cc * 100u; 165838032Speter 165938032Speter /* calculate century cycles shift and cycle index: 166038032Speter * Assuming a century is 5217 weeks, we have to add a cycle 166164562Sgshapiro * shift that is 3 for every 4 centuries, because 3 of the four 166238032Speter * centuries have 5218 weeks. So '(cc*3 + 1) / 4' is the actual 166338032Speter * correction, and the second century is the defective one. 166438032Speter * 166538032Speter * Needs floor division by 4, which is done with masking and 166690792Sgshapiro * shifting. 166790792Sgshapiro */ 166864562Sgshapiro ci = cc * 3u + 1; 166938032Speter cs = uint32_2cpl_to_int32(sflag ^ ((sflag ^ ci) / 4u)); 167038032Speter ci = ci % 4u; 167138032Speter 167290792Sgshapiro /* Get weeks in century. Can use plain division here as all ops 167390792Sgshapiro * are >= 0, and let the compiler sort out the possible 167438032Speter * optimisations. 167538032Speter */ 167638032Speter cw = (yu * 53431u + bctab[ci]) / 1024u; 167738032Speter 167838032Speter return uint32_2cpl_to_int32(cc) * 5217 + cs + cw; 167938032Speter} 168038032Speter 168138032Speter/* 168238032Speter * Given a number of elapsed weeks since the begin of the christian 168364562Sgshapiro * era, split this number into the number of elapsed years in res.hi 168438032Speter * and the excessive number of weeks in res.lo. (That is, res.lo is 168590792Sgshapiro * the number of elapsed weeks in the remaining partial year.) 168673188Sgshapiro */ 168738032Speterntpcal_split 168873188Sgshapiroisocal_split_eraweeks( 168938032Speter int32_t weeks 169038032Speter ) 169138032Speter{ 169238032Speter /* 169338032Speter * use: y = (w * 157 + b[c]) / 8192 as interpolation 169438032Speter */ 169538032Speter 169638032Speter static const uint16_t bctab[4] = { 85, 130, 17, 62 }; 169773188Sgshapiro 169890792Sgshapiro ntpcal_split res; 169938032Speter int32_t cc, ci; 170090792Sgshapiro uint32_t sw, cy, Q, sflag; 170138032Speter 170238032Speter /* Use two fast cycle-split divisions here. This is again 170338032Speter * susceptible to internal overflow, so we check the range. This 170438032Speter * still permits more than +/-20 million years, so this is 170538032Speter * likely a pure academical problem. 170638032Speter * 170738032Speter * We want to execute '(weeks * 4 + 2) /% 20871' under floor 170890792Sgshapiro * division rules in the first step. 170938032Speter */ 171038032Speter sflag = int32_sflag(weeks); 171190792Sgshapiro sw = uint32_saturate(int32_to_uint32_2cpl(weeks), sflag); 171238032Speter sw = 4u * sw + 2; 171338032Speter Q = sflag ^ ((sflag ^ sw) / GREGORIAN_CYCLE_WEEKS); 171442575Speter sw -= Q * GREGORIAN_CYCLE_WEEKS; 171542575Speter ci = Q % 4u; 171642575Speter cc = uint32_2cpl_to_int32(Q); 171742575Speter 171842575Speter /* Split off years; sw >= 0 here! The scaled weeks in the years 171942575Speter * are scaled up by 157 afterwards. 172042575Speter */ 172164562Sgshapiro sw = (sw / 4u) * 157u + bctab[ci]; 172264562Sgshapiro cy = sw / 8192u; /* ws >> 13 , let the compiler sort it out */ 172338032Speter sw = sw % 8192u; /* ws & 8191, let the compiler sort it out */ 172438032Speter 172538032Speter /* assemble elapsed years and downscale the elapsed weeks in 172638032Speter * the year. 172738032Speter */ 172838032Speter res.hi = 100*cc + cy; 172938032Speter res.lo = sw / 157u; 173038032Speter 173190792Sgshapiro return res; 173238032Speter} 173338032Speter 173438032Speter/* 173538032Speter * Given a second in the NTP time scale and a pivot, expand the NTP 173690792Sgshapiro * time stamp around the pivot and convert into an ISO calendar time 173790792Sgshapiro * stamp. 173838032Speter */ 173938032Speterint 174038032Speterisocal_ntp64_to_date( 174138032Speter struct isodate *id, 174238032Speter const vint64 *ntp 174338032Speter ) 174490792Sgshapiro{ 174590792Sgshapiro ntpcal_split ds; 174638032Speter int32_t ts[3]; 174738032Speter uint32_t uw, ud, sflag; 174838032Speter 174938032Speter /* 175064562Sgshapiro * Split NTP time into days and seconds, shift days into CE 175138032Speter * domain and process the parts. 175238032Speter */ 1753168515Sgshapiro ds = ntpcal_daysplit(ntp); 175473188Sgshapiro 175590792Sgshapiro /* split time part */ 175673188Sgshapiro ds.hi += priv_timesplit(ts, ds.lo); 175790792Sgshapiro id->hour = (uint8_t)ts[0]; 175873188Sgshapiro id->minute = (uint8_t)ts[1]; 1759132943Sgshapiro id->second = (uint8_t)ts[2]; 176073188Sgshapiro 176138032Speter /* split days into days and weeks, using floor division in unsigned */ 176238032Speter ds.hi += DAY_NTP_STARTS - 1; /* shift from NTP to RDN */ 176338032Speter sflag = int32_sflag(ds.hi); 176438032Speter ud = int32_to_uint32_2cpl(ds.hi); 176590792Sgshapiro uw = sflag ^ ((sflag ^ ud) / DAYSPERWEEK); 176690792Sgshapiro ud -= uw * DAYSPERWEEK; 176790792Sgshapiro ds.hi = uint32_2cpl_to_int32(uw); 176890792Sgshapiro ds.lo = ud; 176990792Sgshapiro 177090792Sgshapiro id->weekday = (uint8_t)ds.lo + 1; /* weekday result */ 177190792Sgshapiro 177238032Speter /* get year and week in year */ 177338032Speter ds = isocal_split_eraweeks(ds.hi); /* elapsed years&week*/ 177438032Speter id->year = (uint16_t)ds.hi + 1; /* shift to current */ 177538032Speter id->week = (uint8_t )ds.lo + 1; 177638032Speter 177738032Speter return (ds.hi >= 0 && ds.hi < 0x0000FFFF); 177838032Speter} 177938032Speter 178038032Speterint 178138032Speterisocal_ntp_to_date( 178238032Speter struct isodate *id, 178338032Speter uint32_t ntp, 178438032Speter const time_t *piv 178538032Speter ) 178638032Speter{ 178738032Speter vint64 ntp64; 178838032Speter 178938032Speter /* 179038032Speter * Unfold ntp time around current time into NTP domain, then 179138032Speter * convert the full time stamp. 179238032Speter */ 179338032Speter ntp64 = ntpcal_ntp_to_ntp(ntp, piv); 179438032Speter return isocal_ntp64_to_date(id, &ntp64); 179538032Speter} 179638032Speter 179738032Speter/* 179838032Speter * Convert a ISO date spec into a second in the NTP time scale, 179938032Speter * properly truncated to 32 bit. 180038032Speter */ 180138032Spetervint64 180238032Speterisocal_date_to_ntp64( 180338032Speter const struct isodate *id 180438032Speter ) 180538032Speter{ 180638032Speter int32_t weeks, days, secs; 180738032Speter 180838032Speter weeks = isocal_weeks_in_years((int32_t)id->year - 1) 180938032Speter + (int32_t)id->week - 1; 181038032Speter days = weeks * 7 + (int32_t)id->weekday; 181138032Speter /* days is RDN of ISO date now */ 181238032Speter secs = ntpcal_etime_to_seconds(id->hour, id->minute, id->second); 181338032Speter 181438032Speter return ntpcal_dayjoin(days - DAY_NTP_STARTS, secs); 181538032Speter} 181638032Speter 181738032Speteruint32_t 181838032Speterisocal_date_to_ntp( 181938032Speter const struct isodate *id 182038032Speter ) 182138032Speter{ 182238032Speter /* 182338032Speter * Get lower half of 64-bit NTP timestamp from date/time. 182438032Speter */ 182538032Speter return isocal_date_to_ntp64(id).d_s.lo; 182638032Speter} 182738032Speter 182838032Speter/* 182938032Speter * ==================================================================== 183038032Speter * 'basedate' support functions 183138032Speter * ==================================================================== 183238032Speter */ 183338032Speter 183438032Speterstatic int32_t s_baseday = NTP_TO_UNIX_DAYS; 183538032Speter 183638032Speterint32_t 183738032Speterbasedate_eval_buildstamp(void) 183838032Speter{ 183938032Speter struct calendar jd; 184038032Speter int32_t ed; 184138032Speter 184238032Speter if (!ntpcal_get_build_date(&jd)) 184338032Speter return NTP_TO_UNIX_DAYS; 184438032Speter 184538032Speter /* The time zone of the build stamp is unspecified; we remove 184638032Speter * one day to provide a certain slack. And in case somebody 184738032Speter * fiddled with the system clock, we make sure we do not go 184864562Sgshapiro * before the UNIX epoch (1970-01-01). It's probably not possible 184938032Speter * to do this to the clock on most systems, but there are other 185042575Speter * ways to tweak the build stamp. 185190792Sgshapiro */ 185290792Sgshapiro jd.monthday -= 1; 185342575Speter ed = ntpcal_date_to_rd(&jd) - DAY_NTP_STARTS; 185442575Speter return (ed < NTP_TO_UNIX_DAYS) ? NTP_TO_UNIX_DAYS : ed; 185590792Sgshapiro} 185642575Speter 185742575Speterint32_t 185890792Sgshapirobasedate_eval_string( 185990792Sgshapiro const char * str 186090792Sgshapiro ) 186190792Sgshapiro{ 186290792Sgshapiro u_short y,m,d; 186342575Speter u_long ned; 186490792Sgshapiro int rc, nc; 186590792Sgshapiro size_t sl; 186690792Sgshapiro 186790792Sgshapiro sl = strlen(str); 186890792Sgshapiro rc = sscanf(str, "%4hu-%2hu-%2hu%n", &y, &m, &d, &nc); 186990792Sgshapiro if (rc == 3 && (size_t)nc == sl) { 187064562Sgshapiro if (m >= 1 && m <= 12 && d >= 1 && d <= 31) 187138032Speter return ntpcal_edate_to_eradays(y-1, m-1, d) 187290792Sgshapiro - DAY_NTP_STARTS; 187338032Speter goto buildstamp; 187438032Speter } 187538032Speter 187638032Speter rc = sscanf(str, "%lu%n", &ned, &nc); 187738032Speter if (rc == 1 && (size_t)nc == sl) { 187838032Speter if (ned <= INT32_MAX) 187938032Speter return (int32_t)ned; 188038032Speter goto buildstamp; 188138032Speter } 188264562Sgshapiro 188390792Sgshapiro buildstamp: 188438032Speter msyslog(LOG_WARNING, 188538032Speter "basedate string \"%s\" invalid, build date substituted!", 188638032Speter str); 188790792Sgshapiro return basedate_eval_buildstamp(); 188838032Speter} 188938032Speter 189090792Sgshapirouint32_t 189190792Sgshapirobasedate_get_day(void) 189290792Sgshapiro{ 189338032Speter return s_baseday; 189438032Speter} 189538032Speter 189690792Sgshapiroint32_t 189790792Sgshapirobasedate_set_day( 189838032Speter int32_t day 189938032Speter ) 190038032Speter{ 190138032Speter struct calendar jd; 190238032Speter int32_t retv; 190338032Speter 190438032Speter if (day < NTP_TO_UNIX_DAYS) { 190538032Speter msyslog(LOG_WARNING, 190638032Speter "baseday_set_day: invalid day (%lu), UNIX epoch substituted", 190790792Sgshapiro (unsigned long)day); 190838032Speter day = NTP_TO_UNIX_DAYS; 190990792Sgshapiro } 191090792Sgshapiro retv = s_baseday; 191138032Speter s_baseday = day; 191238032Speter ntpcal_rd_to_date(&jd, day + DAY_NTP_STARTS); 191338032Speter msyslog(LOG_INFO, "basedate set to %04hu-%02hu-%02hu", 191490792Sgshapiro jd.year, (u_short)jd.month, (u_short)jd.monthday); 191564562Sgshapiro return retv; 191664562Sgshapiro} 191790792Sgshapiro 191890792Sgshapirotime_t 191990792Sgshapirobasedate_get_eracenter(void) 192090792Sgshapiro{ 192190792Sgshapiro time_t retv; 192264562Sgshapiro retv = (time_t)(s_baseday - NTP_TO_UNIX_DAYS); 192390792Sgshapiro retv *= SECSPERDAY; 192490792Sgshapiro retv += (UINT32_C(1) << 31); 192590792Sgshapiro return retv; 192690792Sgshapiro} 192790792Sgshapiro 192890792Sgshapirotime_t 192990792Sgshapirobasedate_get_erabase(void) 193090792Sgshapiro{ 193190792Sgshapiro time_t retv; 193290792Sgshapiro retv = (time_t)(s_baseday - NTP_TO_UNIX_DAYS); 193390792Sgshapiro retv *= SECSPERDAY; 193490792Sgshapiro return retv; 193566494Sgshapiro} 193638032Speter 193738032Speter/* -*-EOF-*- */ 193890792Sgshapiro