1 /* $NetBSD: ntp_calendar.h,v 1.7 2018/04/07 00:19:52 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 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 35 /* general split representation */ 36 typedef struct { 37 int32_t hi; 38 int32_t lo; 39 } ntpcal_split; 40 41 typedef time_t (*systime_func_ptr)(time_t *); 42 43 /* 44 * set the function for getting the system time. This is mostly used for 45 * unit testing to provide a fixed / shifted time stamp. Setting the 46 * value to NULL restores the original function, that is, 'time()', 47 * which is also the automatic default. 48 */ 49 extern systime_func_ptr ntpcal_set_timefunc(systime_func_ptr); 50 51 /* 52 * days-of-week 53 */ 54 #define CAL_SUNDAY 0 55 #define CAL_MONDAY 1 56 #define CAL_TUESDAY 2 57 #define CAL_WEDNESDAY 3 58 #define CAL_THURSDAY 4 59 #define CAL_FRIDAY 5 60 #define CAL_SATURDAY 6 61 #define CAL_SUNDAY7 7 /* also sunday */ 62 63 /* 64 * Days in each month. 30 days hath September... 65 */ 66 #define JAN 31 67 #define FEB 28 68 #define FEBLEAP 29 69 #define MAR 31 70 #define APR 30 71 #define MAY 31 72 #define JUN 30 73 #define JUL 31 74 #define AUG 31 75 #define SEP 30 76 #define OCT 31 77 #define NOV 30 78 #define DEC 31 79 80 /* 81 * We deal in a 4 year cycle starting at March 1, 1900. We assume 82 * we will only want to deal with dates since then, and not to exceed 83 * the rollover day in 2036. 84 */ 85 #define SECSPERMIN (60) /* seconds per minute */ 86 #define MINSPERHR (60) /* minutes per hour */ 87 #define HRSPERDAY (24) /* hours per day */ 88 #define DAYSPERWEEK (7) /* days per week */ 89 #define DAYSPERYEAR (365) /* days per year */ 90 91 #define SECSPERHR (SECSPERMIN * MINSPERHR) 92 #define SECSPERDAY (SECSPERHR * HRSPERDAY) 93 #define SECSPERWEEK (DAYSPERWEEK * SECSPERDAY) 94 #define SECSPERYEAR (365 * SECSPERDAY) /* regular year */ 95 #define SECSPERLEAPYEAR (366 * SECSPERDAY) /* leap year */ 96 #define SECSPERAVGYEAR 31556952 /* mean year length over 400yrs */ 97 98 /* 99 * Gross hacks. I have illicit knowlege that there won't be overflows 100 * here, the compiler often can't tell this. 101 */ 102 #define TIMES60(val) ((((val)<<4) - (val))<<2) /* *(16 - 1) * 4 */ 103 #define TIMES24(val) (((val)<<4) + ((val)<<3)) /* *16 + *8 */ 104 #define TIMES7(val) (((val)<<3) - (val)) /* *8 - *1 */ 105 #define TIMESDPERC(val) (((val)<<10) + ((val)<<8) \ 106 + ((val)<<7) + ((val)<<5) \ 107 + ((val)<<4) + ((val)<<2) + (val)) /* *big* hack */ 108 109 110 extern const char * const months[12]; 111 extern const char * const daynames[7]; 112 113 extern void caljulian (uint32_t, struct calendar *); 114 extern uint32_t caltontp (const struct calendar *); 115 116 /* 117 * Convert between 'time_t' and 'vint64' 118 */ 119 extern vint64 time_to_vint64(const time_t *); 120 extern time_t vint64_to_time(const vint64 *); 121 122 /* 123 * Get the build date & time. ATTENTION: The time zone is not specified! 124 * This depends entirely on the C compilers' capabilities to properly 125 * expand the '__TIME__' and '__DATE__' macros, as required by the C 126 * standard. 127 */ 128 extern int 129 ntpcal_get_build_date(struct calendar * /* jd */); 130 131 /* 132 * Convert a timestamp in NTP scale to a time_t value in the UN*X 133 * scale with proper epoch unfolding around a given pivot or the 134 * current system time. 135 */ 136 extern vint64 137 ntpcal_ntp_to_time(uint32_t /* ntp */, const time_t * /* pivot */); 138 139 /* 140 * Convert a timestamp in NTP scale to a 64bit seconds value in the NTP 141 * scale with proper epoch unfolding around a given pivot or the current 142 * system time. 143 * Note: The pivot must be given in UN*X time scale! 144 */ 145 extern vint64 146 ntpcal_ntp_to_ntp(uint32_t /* ntp */, const time_t * /* pivot */); 147 148 /* 149 * Split a time stamp in seconds into elapsed days and elapsed seconds 150 * since midnight. 151 */ 152 extern ntpcal_split 153 ntpcal_daysplit(const vint64 *); 154 155 /* 156 * Merge a number of days and a number of seconds into seconds, 157 * expressed in 64 bits to avoid overflow. 158 */ 159 extern vint64 160 ntpcal_dayjoin(int32_t /* days */, int32_t /* seconds */); 161 162 /* Get the number of leap years since epoch for the number of elapsed 163 * full years 164 */ 165 extern int32_t 166 ntpcal_leapyears_in_years(int32_t /* years */); 167 168 /* 169 * Convert elapsed years in Era into elapsed days in Era. 170 */ 171 extern int32_t 172 ntpcal_days_in_years(int32_t /* years */); 173 174 /* 175 * Convert a number of elapsed month in a year into elapsed days 176 * in year. 177 * 178 * The month will be normalized, and 'res.hi' will contain the 179 * excessive years that must be considered when converting the years, 180 * while 'res.lo' will contain the days since start of the 181 * year. (Expect the resulting days to be negative, with a positive 182 * excess! But then, we need no leap year flag, either...) 183 */ 184 extern ntpcal_split 185 ntpcal_days_in_months(int32_t /* months */); 186 187 /* 188 * Convert ELAPSED years/months/days of gregorian calendar to elapsed 189 * days in Gregorian epoch. No range checks done here! 190 */ 191 extern int32_t 192 ntpcal_edate_to_eradays(int32_t /* years */, int32_t /* months */, int32_t /* mdays */); 193 194 /* 195 * Convert a time spec to seconds. No range checks done here! 196 */ 197 extern int32_t 198 ntpcal_etime_to_seconds(int32_t /* hours */, int32_t /* minutes */, int32_t /* seconds */); 199 200 /* 201 * Convert ELAPSED years/months/days of gregorian calendar to elapsed 202 * days in year. 203 * 204 * Note: This will give the true difference to the start of the given year, 205 * even if months & days are off-scale. 206 */ 207 extern int32_t 208 ntpcal_edate_to_yeardays(int32_t /* years */, int32_t /* months */, int32_t /* mdays */); 209 210 /* 211 * Convert the date part of a 'struct tm' (that is, year, month, 212 * day-of-month) into the RataDie of that day. 213 */ 214 extern int32_t 215 ntpcal_tm_to_rd(const struct tm * /* utm */); 216 217 /* 218 * Convert the date part of a 'struct calendar' (that is, year, month, 219 * day-of-month) into the RataDie of that day. 220 */ 221 extern int32_t 222 ntpcal_date_to_rd(const struct calendar * /* jt */); 223 224 /* 225 * Given the number of elapsed days in the calendar era, split this 226 * number into the number of elapsed years in 'res.quot' and the 227 * number of elapsed days of that year in 'res.rem'. 228 * 229 * if 'isleapyear' is not NULL, it will receive an integer that is 0 230 * for regular years and a non-zero value for leap years. 231 * 232 * The input is limited to [-2^30, 2^30-1]. If the days exceed this 233 * range, errno is set to EDOM and the result is saturated. 234 */ 235 extern ntpcal_split 236 ntpcal_split_eradays(int32_t /* days */, int/*BOOL*/ * /* isleapyear */); 237 238 /* 239 * Given a number of elapsed days in a year and a leap year indicator, 240 * split the number of elapsed days into the number of elapsed months 241 * in 'res.quot' and the number of elapsed days of that month in 242 * 'res.rem'. 243 */ 244 extern ntpcal_split 245 ntpcal_split_yeardays(int32_t /* eyd */, int/*BOOL*/ /* isleapyear */); 246 247 /* 248 * Convert a RataDie number into the date part of a 'struct 249 * calendar'. Return 0 if the year is regular year, !0 if the year is 250 * a leap year. 251 */ 252 extern int/*BOOL*/ 253 ntpcal_rd_to_date(struct calendar * /* jt */, int32_t /* rd */); 254 255 /* 256 * Convert a RataDie number into the date part of a 'struct 257 * tm'. Return 0 if the year is regular year, !0 if the year is a leap 258 * year. 259 */ 260 extern int/*BOOL*/ 261 ntpcal_rd_to_tm(struct tm * /* utm */, int32_t /* rd */); 262 263 /* 264 * Take a value of seconds since midnight and split it into hhmmss in 265 * a 'struct calendar'. Return excessive days. 266 */ 267 extern int32_t 268 ntpcal_daysec_to_date(struct calendar * /* jt */, int32_t /* secs */); 269 270 /* 271 * Take the time part of a 'struct calendar' and return the seconds 272 * since midnight. 273 */ 274 extern int32_t 275 ntpcal_date_to_daysec(const struct calendar *); 276 277 /* 278 * Take a value of seconds since midnight and split it into hhmmss in 279 * a 'struct tm'. Return excessive days. 280 */ 281 extern int32_t 282 ntpcal_daysec_to_tm(struct tm * /* utm */, int32_t /* secs */); 283 284 extern int32_t 285 ntpcal_tm_to_daysec(const struct tm * /* utm */); 286 287 /* 288 * convert a year number to rata die of year start 289 */ 290 extern int32_t 291 ntpcal_year_to_ystart(int32_t /* year */); 292 293 /* 294 * For a given RataDie, get the RataDie of the associated year start, 295 * that is, the RataDie of the last January,1st on or before that day. 296 */ 297 extern int32_t 298 ntpcal_rd_to_ystart(int32_t /* rd */); 299 300 /* 301 * convert a RataDie to the RataDie of start of the calendar month. 302 */ 303 extern int32_t 304 ntpcal_rd_to_mstart(int32_t /* year */); 305 306 307 extern int 308 ntpcal_daysplit_to_date(struct calendar * /* jt */, 309 const ntpcal_split * /* ds */, int32_t /* dof */); 310 311 extern int 312 ntpcal_daysplit_to_tm(struct tm * /* utm */, const ntpcal_split * /* ds */, 313 int32_t /* dof */); 314 315 extern int 316 ntpcal_time_to_date(struct calendar * /* jd */, const vint64 * /* ts */); 317 318 extern int32_t 319 ntpcal_periodic_extend(int32_t /* pivot */, int32_t /* value */, 320 int32_t /* cycle */); 321 322 extern int 323 ntpcal_ntp64_to_date(struct calendar * /* jd */, const vint64 * /* ntp */); 324 325 extern int 326 ntpcal_ntp_to_date(struct calendar * /* jd */, uint32_t /* ntp */, 327 const time_t * /* pivot */); 328 329 extern vint64 330 ntpcal_date_to_ntp64(const struct calendar * /* jd */); 331 332 extern uint32_t 333 ntpcal_date_to_ntp(const struct calendar * /* jd */); 334 335 extern time_t 336 ntpcal_date_to_time(const struct calendar * /* jd */); 337 338 /* 339 * ISO week-calendar conversions 340 */ 341 extern int32_t 342 isocal_weeks_in_years(int32_t /* years */); 343 344 /* 345 * The input is limited to [-2^30, 2^30-1]. If the weeks exceed this 346 * range, errno is set to EDOM and the result is saturated. 347 */ 348 extern ntpcal_split 349 isocal_split_eraweeks(int32_t /* weeks */); 350 351 extern int 352 isocal_ntp64_to_date(struct isodate * /* id */, const vint64 * /* ntp */); 353 354 extern int 355 isocal_ntp_to_date(struct isodate * /* id */, uint32_t /* ntp */, 356 const time_t * /* pivot */); 357 358 extern vint64 359 isocal_date_to_ntp64(const struct isodate * /* id */); 360 361 extern uint32_t 362 isocal_date_to_ntp(const struct isodate * /* id */); 363 364 365 /* 366 * day-of-week calculations 367 * 368 * Given a RataDie and a day-of-week, calculate a RDN that is reater-than, 369 * greater-or equal, closest, less-or-equal or less-than the given RDN 370 * and denotes the given day-of-week 371 */ 372 extern int32_t 373 ntpcal_weekday_gt(int32_t /* rdn */, int32_t /* dow */); 374 375 extern int32_t 376 ntpcal_weekday_ge(int32_t /* rdn */, int32_t /* dow */); 377 378 extern int32_t 379 ntpcal_weekday_close(int32_t /* rdn */, int32_t /* dow */); 380 381 extern int32_t 382 ntpcal_weekday_le(int32_t /* rdn */, int32_t /* dow */); 383 384 extern int32_t 385 ntpcal_weekday_lt(int32_t /* rdn */, int32_t /* dow */); 386 387 388 /* 389 * handling of base date spec 390 */ 391 extern int32_t 392 basedate_eval_buildstamp(void); 393 394 extern int32_t 395 basedate_eval_string(const char *str); 396 397 extern int32_t 398 basedate_set_day(int32_t dayno); 399 400 extern uint32_t 401 basedate_get_day(void); 402 403 extern time_t 404 basedate_get_eracenter(void); 405 406 extern time_t 407 basedate_get_erabase(void); 408 409 410 /* 411 * Additional support stuff for Ed Rheingold's calendrical calculations 412 */ 413 414 /* 415 * Start day of NTP time as days past the imaginary date 12/1/1 BC. 416 * (This is the beginning of the Christian Era, or BCE.) 417 */ 418 #define DAY_NTP_STARTS 693596 419 420 /* 421 * Start day of the UNIX epoch. This is the Rata Die of 1970-01-01. 422 */ 423 #define DAY_UNIX_STARTS 719163 424 425 /* 426 * Difference between UN*X and NTP epoch (25567). 427 */ 428 #define NTP_TO_UNIX_DAYS (DAY_UNIX_STARTS - DAY_NTP_STARTS) 429 430 /* 431 * Days in a normal 4 year leap year calendar cycle (1461). 432 */ 433 #define GREGORIAN_NORMAL_LEAP_CYCLE_DAYS (3 * 365 + 366) 434 435 /* 436 * Days in a normal 100 year leap year calendar (36524). We lose a 437 * leap day in years evenly divisible by 100 but not by 400. 438 */ 439 #define GREGORIAN_NORMAL_CENTURY_DAYS \ 440 (25 * GREGORIAN_NORMAL_LEAP_CYCLE_DAYS - 1) 441 442 /* 443 * The Gregorian calendar is based on a 400 year cycle. This is the 444 * number of days in each cycle (146097). We gain a leap day in years 445 * divisible by 400 relative to the "normal" century. 446 */ 447 #define GREGORIAN_CYCLE_DAYS (4 * GREGORIAN_NORMAL_CENTURY_DAYS + 1) 448 449 /* 450 * Number of weeks in 400 years (20871). 451 */ 452 #define GREGORIAN_CYCLE_WEEKS (GREGORIAN_CYCLE_DAYS / 7) 453 454 #define is_leapyear(y) (!((y) % 4) && !(!((y) % 100) && (y) % 400)) 455 456 #endif 457