ntp_calendar.h revision 358659
1/* 2 * ntp_calendar.h - definitions for the calendar time-of-day routine 3 */ 4#ifndef NTP_CALENDAR_H 5#define NTP_CALENDAR_H 6 7#include <time.h> 8 9#include "ntp_types.h" 10 11/* gregorian calendar date */ 12struct calendar { 13 uint16_t year; /* year (A.D.) */ 14 uint16_t yearday; /* day of year, 1 = January 1 */ 15 uint8_t month; /* month, 1 = January */ 16 uint8_t monthday; /* day of month */ 17 uint8_t hour; /* hour of day, midnight = 0 */ 18 uint8_t minute; /* minute of hour */ 19 uint8_t second; /* second of minute */ 20 uint8_t weekday; /* 0..7, 0=Sunday */ 21}; 22typedef struct calendar TCivilDate; 23typedef struct calendar const TcCivilDate; 24 25/* ISO week calendar date */ 26struct isodate { 27 uint16_t year; /* year (A.D.) */ 28 uint8_t week; /* 1..53, week in year */ 29 uint8_t weekday; /* 1..7, 1=Monday */ 30 uint8_t hour; /* hour of day, midnight = 0 */ 31 uint8_t minute; /* minute of hour */ 32 uint8_t second; /* second of minute */ 33}; 34typedef struct isodate TIsoDate; 35typedef struct isodate const TcIsoDate; 36 37/* general split representation */ 38typedef struct { 39 int32_t hi; 40 int32_t lo; 41} ntpcal_split; 42 43typedef time_t (*systime_func_ptr)(time_t *); 44 45/* 46 * set the function for getting the system time. This is mostly used for 47 * unit testing to provide a fixed / shifted time stamp. Setting the 48 * value to NULL restores the original function, that is, 'time()', 49 * which is also the automatic default. 50 */ 51extern systime_func_ptr ntpcal_set_timefunc(systime_func_ptr); 52 53/* 54 * days-of-week 55 */ 56#define CAL_SUNDAY 0 57#define CAL_MONDAY 1 58#define CAL_TUESDAY 2 59#define CAL_WEDNESDAY 3 60#define CAL_THURSDAY 4 61#define CAL_FRIDAY 5 62#define CAL_SATURDAY 6 63#define CAL_SUNDAY7 7 /* also sunday */ 64 65/* 66 * Days in each month. 30 days hath September... 67 */ 68#define JAN 31 69#define FEB 28 70#define FEBLEAP 29 71#define MAR 31 72#define APR 30 73#define MAY 31 74#define JUN 30 75#define JUL 31 76#define AUG 31 77#define SEP 30 78#define OCT 31 79#define NOV 30 80#define DEC 31 81 82/* 83 * We deal in a 4 year cycle starting at March 1, 1900. We assume 84 * we will only want to deal with dates since then, and not to exceed 85 * the rollover day in 2036. 86 */ 87#define SECSPERMIN (60) /* seconds per minute */ 88#define MINSPERHR (60) /* minutes per hour */ 89#define HRSPERDAY (24) /* hours per day */ 90#define DAYSPERWEEK (7) /* days per week */ 91#define DAYSPERYEAR (365) /* days per year */ 92 93#define SECSPERHR (SECSPERMIN * MINSPERHR) 94#define SECSPERDAY (SECSPERHR * HRSPERDAY) 95#define SECSPERWEEK (DAYSPERWEEK * SECSPERDAY) 96#define SECSPERYEAR (365 * SECSPERDAY) /* regular year */ 97#define SECSPERLEAPYEAR (366 * SECSPERDAY) /* leap year */ 98#define SECSPERAVGYEAR 31556952 /* mean year length over 400yrs */ 99 100#define GPSWEEKS 1024 /* GPS week cycle */ 101/* 102 * Gross hacks. I have illicit knowlege that there won't be overflows 103 * here, the compiler often can't tell this. 104 */ 105#define TIMES60(val) ((((val)<<4) - (val))<<2) /* *(16 - 1) * 4 */ 106#define TIMES24(val) (((val)<<4) + ((val)<<3)) /* *16 + *8 */ 107#define TIMES7(val) (((val)<<3) - (val)) /* *8 - *1 */ 108#define TIMESDPERC(val) (((val)<<10) + ((val)<<8) \ 109 + ((val)<<7) + ((val)<<5) \ 110 + ((val)<<4) + ((val)<<2) + (val)) /* *big* hack */ 111 112 113extern const char * const months[12]; 114extern const char * const daynames[7]; 115 116extern char * ntpcal_iso8601std(char*, size_t, struct calendar const*); 117extern void caljulian (uint32_t, struct calendar *); 118extern uint32_t caltontp (const struct calendar *); 119 120/* 121 * Convert between 'time_t' and 'vint64' 122 */ 123extern vint64 time_to_vint64(const time_t *); 124extern time_t vint64_to_time(const vint64 *); 125 126/* 127 * Get the build date & time. ATTENTION: The time zone is not specified! 128 * This depends entirely on the C compilers' capabilities to properly 129 * expand the '__TIME__' and '__DATE__' macros, as required by the C 130 * standard. 131 */ 132extern int 133ntpcal_get_build_date(struct calendar * /* jd */); 134 135/* 136 * Convert a timestamp in NTP scale to a time_t value in the UN*X 137 * scale with proper epoch unfolding around a given pivot or the 138 * current system time. 139 */ 140extern vint64 141ntpcal_ntp_to_time(uint32_t /* ntp */, const time_t * /* pivot */); 142 143/* 144 * Convert a timestamp in NTP scale to a 64bit seconds value in the NTP 145 * scale with proper epoch unfolding around a given pivot or the current 146 * system time. 147 * Note: The pivot must be given in UN*X time scale! 148 */ 149extern vint64 150ntpcal_ntp_to_ntp(uint32_t /* ntp */, const time_t * /* pivot */); 151 152/* 153 * Split a time stamp in seconds into elapsed days and elapsed seconds 154 * since midnight. 155 */ 156extern ntpcal_split 157ntpcal_daysplit(const vint64 *); 158 159/* 160 * Split a time stamp in seconds into elapsed weeks and elapsed seconds 161 * since start of week. 162 */ 163extern ntpcal_split 164ntpcal_weeksplit(const vint64 *); 165 166/* 167 * Merge a number of days and a number of seconds into seconds, 168 * expressed in 64 bits to avoid overflow. 169 */ 170extern vint64 171ntpcal_dayjoin(int32_t /* days */, int32_t /* seconds */); 172 173/* 174 * Merge a number of weeks and a number of seconds into seconds, 175 * expressed in 64 bits to avoid overflow. 176 */ 177extern vint64 178ntpcal_weekjoin(int32_t /* weeks */, int32_t /* seconds */); 179 180/* Get the number of leap years since epoch for the number of elapsed 181 * full years 182 */ 183extern int32_t 184ntpcal_leapyears_in_years(int32_t /* years */); 185 186/* 187 * Convert elapsed years in Era into elapsed days in Era. 188 */ 189extern int32_t 190ntpcal_days_in_years(int32_t /* years */); 191 192/* 193 * Convert a number of elapsed month in a year into elapsed days 194 * in year. 195 * 196 * The month will be normalized, and 'res.hi' will contain the 197 * excessive years that must be considered when converting the years, 198 * while 'res.lo' will contain the days since start of the 199 * year. (Expect the resulting days to be negative, with a positive 200 * excess! But then, we need no leap year flag, either...) 201 */ 202extern ntpcal_split 203ntpcal_days_in_months(int32_t /* months */); 204 205/* 206 * Convert ELAPSED years/months/days of gregorian calendar to elapsed 207 * days in Gregorian epoch. No range checks done here! 208 */ 209extern int32_t 210ntpcal_edate_to_eradays(int32_t /* years */, int32_t /* months */, int32_t /* mdays */); 211 212/* 213 * Convert a time spec to seconds. No range checks done here! 214 */ 215extern int32_t 216ntpcal_etime_to_seconds(int32_t /* hours */, int32_t /* minutes */, int32_t /* seconds */); 217 218/* 219 * Convert ELAPSED years/months/days of gregorian calendar to elapsed 220 * days in year. 221 * 222 * Note: This will give the true difference to the start of the given year, 223 * even if months & days are off-scale. 224 */ 225extern int32_t 226ntpcal_edate_to_yeardays(int32_t /* years */, int32_t /* months */, int32_t /* mdays */); 227 228/* 229 * Convert the date part of a 'struct tm' (that is, year, month, 230 * day-of-month) into the RataDie of that day. 231 */ 232extern int32_t 233ntpcal_tm_to_rd(const struct tm * /* utm */); 234 235/* 236 * Convert the date part of a 'struct calendar' (that is, year, month, 237 * day-of-month) into the RataDie of that day. 238 */ 239extern int32_t 240ntpcal_date_to_rd(const struct calendar * /* jt */); 241 242/* 243 * Given the number of elapsed days in the calendar era, split this 244 * number into the number of elapsed years in 'res.quot' and the 245 * number of elapsed days of that year in 'res.rem'. 246 * 247 * if 'isleapyear' is not NULL, it will receive an integer that is 0 248 * for regular years and a non-zero value for leap years. 249 * 250 * The input is limited to [-2^30, 2^30-1]. If the days exceed this 251 * range, errno is set to EDOM and the result is saturated. 252 */ 253extern ntpcal_split 254ntpcal_split_eradays(int32_t /* days */, int/*BOOL*/ * /* isleapyear */); 255 256/* 257 * Given a number of elapsed days in a year and a leap year indicator, 258 * split the number of elapsed days into the number of elapsed months 259 * in 'res.quot' and the number of elapsed days of that month in 260 * 'res.rem'. 261 */ 262extern ntpcal_split 263ntpcal_split_yeardays(int32_t /* eyd */, int/*BOOL*/ /* isleapyear */); 264 265/* 266 * Convert a RataDie number into the date part of a 'struct 267 * calendar'. Return 0 if the year is regular year, !0 if the year is 268 * a leap year. 269 */ 270extern int/*BOOL*/ 271ntpcal_rd_to_date(struct calendar * /* jt */, int32_t /* rd */); 272 273/* 274 * Convert a RataDie number into the date part of a 'struct 275 * tm'. Return 0 if the year is regular year, !0 if the year is a leap 276 * year. 277 */ 278extern int/*BOOL*/ 279ntpcal_rd_to_tm(struct tm * /* utm */, int32_t /* rd */); 280 281/* 282 * Take a value of seconds since midnight and split it into hhmmss in 283 * a 'struct calendar'. Return excessive days. 284 */ 285extern int32_t 286ntpcal_daysec_to_date(struct calendar * /* jt */, int32_t /* secs */); 287 288/* 289 * Take the time part of a 'struct calendar' and return the seconds 290 * since midnight. 291 */ 292extern int32_t 293ntpcal_date_to_daysec(const struct calendar *); 294 295/* 296 * Take a value of seconds since midnight and split it into hhmmss in 297 * a 'struct tm'. Return excessive days. 298 */ 299extern int32_t 300ntpcal_daysec_to_tm(struct tm * /* utm */, int32_t /* secs */); 301 302extern int32_t 303ntpcal_tm_to_daysec(const struct tm * /* utm */); 304 305/* 306 * convert a year number to rata die of year start 307 */ 308extern int32_t 309ntpcal_year_to_ystart(int32_t /* year */); 310 311/* 312 * For a given RataDie, get the RataDie of the associated year start, 313 * that is, the RataDie of the last January,1st on or before that day. 314 */ 315extern int32_t 316ntpcal_rd_to_ystart(int32_t /* rd */); 317 318/* 319 * convert a RataDie to the RataDie of start of the calendar month. 320 */ 321extern int32_t 322ntpcal_rd_to_mstart(int32_t /* year */); 323 324 325extern int 326ntpcal_daysplit_to_date(struct calendar * /* jt */, 327 const ntpcal_split * /* ds */, int32_t /* dof */); 328 329extern int 330ntpcal_daysplit_to_tm(struct tm * /* utm */, const ntpcal_split * /* ds */, 331 int32_t /* dof */); 332 333extern int 334ntpcal_time_to_date(struct calendar * /* jd */, const vint64 * /* ts */); 335 336extern int32_t 337ntpcal_periodic_extend(int32_t /* pivot */, int32_t /* value */, 338 int32_t /* cycle */); 339 340extern int 341ntpcal_ntp64_to_date(struct calendar * /* jd */, const vint64 * /* ntp */); 342 343extern int 344ntpcal_ntp_to_date(struct calendar * /* jd */, uint32_t /* ntp */, 345 const time_t * /* pivot */); 346 347extern vint64 348ntpcal_date_to_ntp64(const struct calendar * /* jd */); 349 350extern uint32_t 351ntpcal_date_to_ntp(const struct calendar * /* jd */); 352 353extern time_t 354ntpcal_date_to_time(const struct calendar * /* jd */); 355 356/* 357 * ISO week-calendar conversions 358 */ 359extern int32_t 360isocal_weeks_in_years(int32_t /* years */); 361 362/* 363 * The input is limited to [-2^30, 2^30-1]. If the weeks exceed this 364 * range, errno is set to EDOM and the result is saturated. 365 */ 366extern ntpcal_split 367isocal_split_eraweeks(int32_t /* weeks */); 368 369extern int 370isocal_ntp64_to_date(struct isodate * /* id */, const vint64 * /* ntp */); 371 372extern int 373isocal_ntp_to_date(struct isodate * /* id */, uint32_t /* ntp */, 374 const time_t * /* pivot */); 375 376extern vint64 377isocal_date_to_ntp64(const struct isodate * /* id */); 378 379extern uint32_t 380isocal_date_to_ntp(const struct isodate * /* id */); 381 382 383/* 384 * day-of-week calculations 385 * 386 * Given a RataDie and a day-of-week, calculate a RDN that is reater-than, 387 * greater-or equal, closest, less-or-equal or less-than the given RDN 388 * and denotes the given day-of-week 389 */ 390extern int32_t 391ntpcal_weekday_gt(int32_t /* rdn */, int32_t /* dow */); 392 393extern int32_t 394ntpcal_weekday_ge(int32_t /* rdn */, int32_t /* dow */); 395 396extern int32_t 397ntpcal_weekday_close(int32_t /* rdn */, int32_t /* dow */); 398 399extern int32_t 400ntpcal_weekday_le(int32_t /* rdn */, int32_t /* dow */); 401 402extern int32_t 403ntpcal_weekday_lt(int32_t /* rdn */, int32_t /* dow */); 404 405 406/* 407 * handling of base date spec 408 */ 409extern int32_t 410basedate_eval_buildstamp(void); 411 412extern int32_t 413basedate_eval_string(const char *str); 414 415extern int32_t 416basedate_set_day(int32_t dayno); 417 418extern uint32_t 419basedate_get_day(void); 420 421extern time_t 422basedate_get_eracenter(void); 423 424extern time_t 425basedate_get_erabase(void); 426 427extern uint32_t 428basedate_get_gpsweek(void); 429 430extern uint32_t 431basedate_expand_gpsweek(unsigned short weekno); 432 433/* 434 * Additional support stuff for Ed Rheingold's calendrical calculations 435 */ 436 437/* 438 * Start day of NTP time as days past 0000-12-31 in the proleptic 439 * Gregorian calendar. (So 0001-01-01 is day number 1; this is the Rata 440 * Die counting scheme used by Ed Rheingold in his book "Calendrical 441 * Calculations".) 442 */ 443#define DAY_NTP_STARTS 693596 444 445/* 446 * Start day of the UNIX epoch. This is the Rata Die of 1970-01-01. 447 */ 448#define DAY_UNIX_STARTS 719163 449 450/* 451 * Start day of the GPS epoch. This is the Rata Die of 1980-01-06 452 */ 453#define DAY_GPS_STARTS 722820 454 455/* 456 * Difference between UN*X and NTP epoch (25567). 457 */ 458#define NTP_TO_UNIX_DAYS (DAY_UNIX_STARTS - DAY_NTP_STARTS) 459 460/* 461 * Difference between GPS and NTP epoch (29224) 462 */ 463#define NTP_TO_GPS_DAYS (DAY_GPS_STARTS - DAY_NTP_STARTS) 464 465/* 466 * Days in a normal 4 year leap year calendar cycle (1461). 467 */ 468#define GREGORIAN_NORMAL_LEAP_CYCLE_DAYS (4 * 365 + 1) 469 470/* 471 * Days in a normal 100 year leap year calendar (36524). We lose a 472 * leap day in years evenly divisible by 100 but not by 400. 473 */ 474#define GREGORIAN_NORMAL_CENTURY_DAYS \ 475 (25 * GREGORIAN_NORMAL_LEAP_CYCLE_DAYS - 1) 476 477/* 478 * The Gregorian calendar is based on a 400 year cycle. This is the 479 * number of days in each cycle (146097). We gain a leap day in years 480 * divisible by 400 relative to the "normal" century. 481 */ 482#define GREGORIAN_CYCLE_DAYS (4 * GREGORIAN_NORMAL_CENTURY_DAYS + 1) 483 484/* 485 * Number of weeks in 400 years (20871). 486 */ 487#define GREGORIAN_CYCLE_WEEKS (GREGORIAN_CYCLE_DAYS / 7) 488 489/* 490 * Is a Greogorian calendar year a leap year? The obvious solution is to 491 * test the expression 492 * 493 * (y % 4 == 0) && ((y % 100 != 0) || (y % 400 == 0)) 494 * 495 * This needs (in theory) 2 true divisions -- most compilers check the 496 * (mod 4) condition by doing a bit test. Some compilers have been 497 * even observed to partially fuse the (mod 100) and (mod 400) test, 498 * but there is an alternative formula that gives the compiler even 499 * better chances: 500 * 501 * (y % 4 == 0) && ((y % 16 == 0) || (y % 25 != 0)) 502 * 503 * The order of checks is chosen so that the shorcut evaluation can fix 504 * the result as soon as possible. And the compiler has to do only one 505 * true division here -- the (mod 4) and (mod 16) can be done with 506 * direct bit tests. *If* the compiler chooses to do so. 507 * 508 * The deduction is as follows: rewrite the standard formula as 509 * (y % 4 == 0) && ((y % 4*25 != 0) || (y % 16*25 == 0)) 510 * 511 * then split the congruences: 512 * (y % 4 == 0) && ((y % 4 != 0 || y % 25 != 0) || (y % 16 == 0 && y % 25 == 0)) 513 * 514 * eliminate the 1st inner term, as it is provably false: 515 * (y % 4 == 0) && (y % 25 != 0 || (y % 16 == 0 && y % 25 == 0)) 516 * 517 * Use the distributive laws on the second major group: 518 * (y % 4 == 0) && ((y % 25 != 0 || y % 16 == 0) && (y % 25 != 0 || y % 25 == 0)) 519 * 520 * Eliminate the constant term, reorder, and voila: 521 */ 522 523static inline int 524is_leapyear(int32_t y) { 525 return !(y % 4) && (!(y % 16) || (y % 25)); 526} 527/* The (mod 4) test eliminates 3/4 (or 12/16) of all values. 528 * The (mod 16) test eliminates another 1/16 of all values. 529 * 3/16 of all values reach the final division. 530 * Assuming that the true division is the most costly operation, this 531 * sequence should give most bang for the buck. 532 */ 533 534/* misc */ 535extern int u32mod7(uint32_t x); 536extern int i32mod7(int32_t x); 537extern uint32_t i32fmod(int32_t x, uint32_t d); 538 539extern int32_t ntpcal_expand_century(uint32_t y, uint32_t m, uint32_t d, uint32_t wd); 540 541#endif 542