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