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