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 */ 12 struct 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 }; 22 typedef struct calendar TCivilDate; 23 typedef struct calendar const TcCivilDate; 24 25 /* ISO week calendar date */ 26 struct 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 }; 34 typedef struct isodate TIsoDate; 35 typedef struct isodate const TcIsoDate; 36 37 /* general split representation */ 38 typedef struct { 39 int32_t hi; 40 int32_t lo; 41 } ntpcal_split; 42 43 typedef 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 */ 51 extern 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 113 extern const char * const months[12]; 114 extern const char * const daynames[7]; 115 116 extern char * ntpcal_iso8601std(char*, size_t, struct calendar const*); 117 extern void caljulian (uint32_t, struct calendar *); 118 extern uint32_t caltontp (const struct calendar *); 119 120 /* 121 * Convert between 'time_t' and 'vint64' 122 */ 123 extern vint64 time_to_vint64(const time_t *); 124 extern 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 */ 132 extern int 133 ntpcal_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 */ 140 extern vint64 141 ntpcal_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 */ 149 extern vint64 150 ntpcal_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 */ 156 extern ntpcal_split 157 ntpcal_daysplit(const vint64 *); 158 159 /* 160 * Split a time stamp in seconds into elapsed weeks and elapsed seconds 161 * since start of week. 162 */ 163 extern ntpcal_split 164 ntpcal_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 */ 170 extern vint64 171 ntpcal_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 */ 177 extern vint64 178 ntpcal_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 */ 183 extern int32_t 184 ntpcal_leapyears_in_years(int32_t /* years */); 185 186 /* 187 * Convert elapsed years in Era into elapsed days in Era. 188 */ 189 extern int32_t 190 ntpcal_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 */ 202 extern ntpcal_split 203 ntpcal_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 */ 209 extern int32_t 210 ntpcal_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 */ 215 extern int32_t 216 ntpcal_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 */ 225 extern int32_t 226 ntpcal_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 */ 232 extern int32_t 233 ntpcal_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 */ 239 extern int32_t 240 ntpcal_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 */ 253 extern ntpcal_split 254 ntpcal_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 */ 262 extern ntpcal_split 263 ntpcal_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 */ 270 extern int/*BOOL*/ 271 ntpcal_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 */ 278 extern int/*BOOL*/ 279 ntpcal_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 */ 285 extern int32_t 286 ntpcal_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 */ 292 extern int32_t 293 ntpcal_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 */ 299 extern int32_t 300 ntpcal_daysec_to_tm(struct tm * /* utm */, int32_t /* secs */); 301 302 extern int32_t 303 ntpcal_tm_to_daysec(const struct tm * /* utm */); 304 305 /* 306 * convert a year number to rata die of year start 307 */ 308 extern int32_t 309 ntpcal_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 */ 315 extern int32_t 316 ntpcal_rd_to_ystart(int32_t /* rd */); 317 318 /* 319 * convert a RataDie to the RataDie of start of the calendar month. 320 */ 321 extern int32_t 322 ntpcal_rd_to_mstart(int32_t /* year */); 323 324 325 extern int 326 ntpcal_daysplit_to_date(struct calendar * /* jt */, 327 const ntpcal_split * /* ds */, int32_t /* dof */); 328 329 extern int 330 ntpcal_daysplit_to_tm(struct tm * /* utm */, const ntpcal_split * /* ds */, 331 int32_t /* dof */); 332 333 extern int 334 ntpcal_time_to_date(struct calendar * /* jd */, const vint64 * /* ts */); 335 336 extern int32_t 337 ntpcal_periodic_extend(int32_t /* pivot */, int32_t /* value */, 338 int32_t /* cycle */); 339 340 extern int 341 ntpcal_ntp64_to_date(struct calendar * /* jd */, const vint64 * /* ntp */); 342 343 extern int 344 ntpcal_ntp_to_date(struct calendar * /* jd */, uint32_t /* ntp */, 345 const time_t * /* pivot */); 346 347 extern vint64 348 ntpcal_date_to_ntp64(const struct calendar * /* jd */); 349 350 extern uint32_t 351 ntpcal_date_to_ntp(const struct calendar * /* jd */); 352 353 extern time_t 354 ntpcal_date_to_time(const struct calendar * /* jd */); 355 356 /* 357 * ISO week-calendar conversions 358 */ 359 extern int32_t 360 isocal_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 */ 366 extern ntpcal_split 367 isocal_split_eraweeks(int32_t /* weeks */); 368 369 extern int 370 isocal_ntp64_to_date(struct isodate * /* id */, const vint64 * /* ntp */); 371 372 extern int 373 isocal_ntp_to_date(struct isodate * /* id */, uint32_t /* ntp */, 374 const time_t * /* pivot */); 375 376 extern vint64 377 isocal_date_to_ntp64(const struct isodate * /* id */); 378 379 extern uint32_t 380 isocal_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 */ 390 extern int32_t 391 ntpcal_weekday_gt(int32_t /* rdn */, int32_t /* dow */); 392 393 extern int32_t 394 ntpcal_weekday_ge(int32_t /* rdn */, int32_t /* dow */); 395 396 extern int32_t 397 ntpcal_weekday_close(int32_t /* rdn */, int32_t /* dow */); 398 399 extern int32_t 400 ntpcal_weekday_le(int32_t /* rdn */, int32_t /* dow */); 401 402 extern int32_t 403 ntpcal_weekday_lt(int32_t /* rdn */, int32_t /* dow */); 404 405 406 /* 407 * handling of base date spec 408 */ 409 extern int32_t 410 basedate_eval_buildstamp(void); 411 412 extern int32_t 413 basedate_eval_string(const char *str); 414 415 extern int32_t 416 basedate_set_day(int32_t dayno); 417 418 extern uint32_t 419 basedate_get_day(void); 420 421 extern time_t 422 basedate_get_eracenter(void); 423 424 extern time_t 425 basedate_get_erabase(void); 426 427 extern uint32_t 428 basedate_get_gpsweek(void); 429 430 extern uint32_t 431 basedate_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 523 static inline int 524 is_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 */ 535 extern int u32mod7(uint32_t x); 536 extern int i32mod7(int32_t x); 537 extern uint32_t i32fmod(int32_t x, uint32_t d); 538 539 extern int32_t ntpcal_expand_century(uint32_t y, uint32_t m, uint32_t d, uint32_t wd); 540 541 #endif 542