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 23 /* ISO week calendar date */ 24 struct 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 */ 34 typedef struct { 35 int32_t hi; 36 int32_t lo; 37 } ntpcal_split; 38 39 typedef 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 */ 47 extern 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 DAYSPERYEAR (365) /* days per year */ 87 88 #define SECSPERHR (SECSPERMIN * MINSPERHR) 89 #define SECSPERDAY (SECSPERHR * HRSPERDAY) 90 #define SECSPERYEAR (365 * SECSPERDAY) /* regular year */ 91 #define SECSPERLEAPYEAR (366 * SECSPERDAY) /* leap year */ 92 #define SECSPERAVGYEAR 31556952 /* mean year length over 400yrs */ 93 94 /* 95 * Gross hacks. I have illicit knowlege that there won't be overflows 96 * here, the compiler often can't tell this. 97 */ 98 #define TIMES60(val) ((((val)<<4) - (val))<<2) /* *(16 - 1) * 4 */ 99 #define TIMES24(val) (((val)<<4) + ((val)<<3)) /* *16 + *8 */ 100 #define TIMES7(val) (((val)<<3) - (val)) /* *8 - *1 */ 101 #define TIMESDPERC(val) (((val)<<10) + ((val)<<8) \ 102 + ((val)<<7) + ((val)<<5) \ 103 + ((val)<<4) + ((val)<<2) + (val)) /* *big* hack */ 104 105 106 extern const char * const months[12]; 107 extern const char * const daynames[7]; 108 109 extern void caljulian (uint32_t, struct calendar *); 110 extern uint32_t caltontp (const struct calendar *); 111 112 /* 113 * Convert between 'time_t' and 'vint64' 114 */ 115 extern vint64 time_to_vint64(const time_t *); 116 extern time_t vint64_to_time(const vint64 *); 117 118 /* 119 * Get the build date & time. ATTENTION: The time zone is not specified! 120 * This depends entirely on the C compilers' capabilities to properly 121 * expand the '__TIME__' and '__DATE__' macros, as required by the C 122 * standard. 123 */ 124 extern int 125 ntpcal_get_build_date(struct calendar * /* jd */); 126 127 /* 128 * Convert a timestamp in NTP scale to a time_t value in the UN*X 129 * scale with proper epoch unfolding around a given pivot or the 130 * current system time. 131 */ 132 extern vint64 133 ntpcal_ntp_to_time(uint32_t /* ntp */, const time_t * /* pivot */); 134 135 /* 136 * Convert a timestamp in NTP scale to a 64bit seconds value in the NTP 137 * scale with proper epoch unfolding around a given pivot or the current 138 * system time. 139 * Note: The pivot must be given in UN*X time scale! 140 */ 141 extern vint64 142 ntpcal_ntp_to_ntp(uint32_t /* ntp */, const time_t * /* pivot */); 143 144 /* 145 * Split a time stamp in seconds into elapsed days and elapsed seconds 146 * since midnight. 147 */ 148 extern ntpcal_split 149 ntpcal_daysplit(const vint64 *); 150 151 /* 152 * Merge a number of days and a number of seconds into seconds, 153 * expressed in 64 bits to avoid overflow. 154 */ 155 extern vint64 156 ntpcal_dayjoin(int32_t /* days */, int32_t /* seconds */); 157 158 /* 159 * Convert elapsed years in Era into elapsed days in Era. 160 */ 161 extern int32_t 162 ntpcal_days_in_years(int32_t /* years */); 163 164 /* 165 * Convert a number of elapsed month in a year into elapsed days 166 * in year. 167 * 168 * The month will be normalized, and 'res.hi' will contain the 169 * excessive years that must be considered when converting the years, 170 * while 'res.lo' will contain the days since start of the 171 * year. (Expect the resulting days to be negative, with a positive 172 * excess! But then, we need no leap year flag, either...) 173 */ 174 extern ntpcal_split 175 ntpcal_days_in_months(int32_t /* months */); 176 177 /* 178 * Convert ELAPSED years/months/days of gregorian calendar to elapsed 179 * days in Gregorian epoch. No range checks done here! 180 */ 181 extern int32_t 182 ntpcal_edate_to_eradays(int32_t /* years */, int32_t /* months */, int32_t /* mdays */); 183 184 /* 185 * Convert a time spec to seconds. No range checks done here! 186 */ 187 extern int32_t 188 ntpcal_etime_to_seconds(int32_t /* hours */, int32_t /* minutes */, int32_t /* seconds */); 189 190 /* 191 * Convert ELAPSED years/months/days of gregorian calendar to elapsed 192 * days in year. 193 * 194 * Note: This will give the true difference to the start of the given year, 195 * even if months & days are off-scale. 196 */ 197 extern int32_t 198 ntpcal_edate_to_yeardays(int32_t /* years */, int32_t /* months */, int32_t /* mdays */); 199 200 /* 201 * Convert the date part of a 'struct tm' (that is, year, month, 202 * day-of-month) into the RataDie of that day. 203 */ 204 extern int32_t 205 ntpcal_tm_to_rd(const struct tm * /* utm */); 206 207 /* 208 * Convert the date part of a 'struct calendar' (that is, year, month, 209 * day-of-month) into the RataDie of that day. 210 */ 211 extern int32_t 212 ntpcal_date_to_rd(const struct calendar * /* jt */); 213 214 /* 215 * Given the number of elapsed days in the calendar era, split this 216 * number into the number of elapsed years in 'res.quot' and the 217 * number of elapsed days of that year in 'res.rem'. 218 * 219 * if 'isleapyear' is not NULL, it will receive an integer that is 0 220 * for regular years and a non-zero value for leap years. 221 */ 222 extern ntpcal_split 223 ntpcal_split_eradays(int32_t /* days */, int/*BOOL*/ * /* isleapyear */); 224 225 /* 226 * Given a number of elapsed days in a year and a leap year indicator, 227 * split the number of elapsed days into the number of elapsed months 228 * in 'res.quot' and the number of elapsed days of that month in 229 * 'res.rem'. 230 */ 231 extern ntpcal_split 232 ntpcal_split_yeardays(int32_t /* eyd */, int/*BOOL*/ /* isleapyear */); 233 234 /* 235 * Convert a RataDie number into the date part of a 'struct 236 * calendar'. Return 0 if the year is regular year, !0 if the year is 237 * a leap year. 238 */ 239 extern int/*BOOL*/ 240 ntpcal_rd_to_date(struct calendar * /* jt */, int32_t /* rd */); 241 242 /* 243 * Convert a RataDie number into the date part of a 'struct 244 * tm'. Return 0 if the year is regular year, !0 if the year is a leap 245 * year. 246 */ 247 extern int/*BOOL*/ 248 ntpcal_rd_to_tm(struct tm * /* utm */, int32_t /* rd */); 249 250 /* 251 * Take a value of seconds since midnight and split it into hhmmss in 252 * a 'struct calendar'. Return excessive days. 253 */ 254 extern int32_t 255 ntpcal_daysec_to_date(struct calendar * /* jt */, int32_t /* secs */); 256 257 /* 258 * Take the time part of a 'struct calendar' and return the seconds 259 * since midnight. 260 */ 261 extern int32_t 262 ntpcal_date_to_daysec(const struct calendar *); 263 264 /* 265 * Take a value of seconds since midnight and split it into hhmmss in 266 * a 'struct tm'. Return excessive days. 267 */ 268 extern int32_t 269 ntpcal_daysec_to_tm(struct tm * /* utm */, int32_t /* secs */); 270 271 extern int32_t 272 ntpcal_tm_to_daysec(const struct tm * /* utm */); 273 274 /* 275 * convert a year number to rata die of year start 276 */ 277 extern int32_t 278 ntpcal_year_to_ystart(int32_t /* year */); 279 280 /* 281 * For a given RataDie, get the RataDie of the associated year start, 282 * that is, the RataDie of the last January,1st on or before that day. 283 */ 284 extern int32_t 285 ntpcal_rd_to_ystart(int32_t /* rd */); 286 287 /* 288 * convert a RataDie to the RataDie of start of the calendar month. 289 */ 290 extern int32_t 291 ntpcal_rd_to_mstart(int32_t /* year */); 292 293 294 extern int 295 ntpcal_daysplit_to_date(struct calendar * /* jt */, 296 const ntpcal_split * /* ds */, int32_t /* dof */); 297 298 extern int 299 ntpcal_daysplit_to_tm(struct tm * /* utm */, const ntpcal_split * /* ds */, 300 int32_t /* dof */); 301 302 extern int 303 ntpcal_time_to_date(struct calendar * /* jd */, const vint64 * /* ts */); 304 305 extern int32_t 306 ntpcal_periodic_extend(int32_t /* pivot */, int32_t /* value */, 307 int32_t /* cycle */); 308 309 extern int 310 ntpcal_ntp64_to_date(struct calendar * /* jd */, const vint64 * /* ntp */); 311 312 extern int 313 ntpcal_ntp_to_date(struct calendar * /* jd */, uint32_t /* ntp */, 314 const time_t * /* pivot */); 315 316 extern vint64 317 ntpcal_date_to_ntp64(const struct calendar * /* jd */); 318 319 extern uint32_t 320 ntpcal_date_to_ntp(const struct calendar * /* jd */); 321 322 extern time_t 323 ntpcal_date_to_time(const struct calendar * /* jd */); 324 325 /* 326 * ISO week-calendar conversions 327 */ 328 extern int32_t 329 isocal_weeks_in_years(int32_t /* years */); 330 331 extern ntpcal_split 332 isocal_split_eraweeks(int32_t /* weeks */); 333 334 extern int 335 isocal_ntp64_to_date(struct isodate * /* id */, const vint64 * /* ntp */); 336 337 extern int 338 isocal_ntp_to_date(struct isodate * /* id */, uint32_t /* ntp */, 339 const time_t * /* pivot */); 340 341 extern vint64 342 isocal_date_to_ntp64(const struct isodate * /* id */); 343 344 extern uint32_t 345 isocal_date_to_ntp(const struct isodate * /* id */); 346 347 348 /* 349 * day-of-week calculations 350 * 351 * Given a RataDie and a day-of-week, calculate a RDN that is reater-than, 352 * greater-or equal, closest, less-or-equal or less-than the given RDN 353 * and denotes the given day-of-week 354 */ 355 extern int32_t 356 ntpcal_weekday_gt(int32_t /* rdn */, int32_t /* dow */); 357 358 extern int32_t 359 ntpcal_weekday_ge(int32_t /* rdn */, int32_t /* dow */); 360 361 extern int32_t 362 ntpcal_weekday_close(int32_t /* rdn */, int32_t /* dow */); 363 364 extern int32_t 365 ntpcal_weekday_le(int32_t /* rdn */, int32_t /* dow */); 366 367 extern int32_t 368 ntpcal_weekday_lt(int32_t /* rdn */, int32_t /* dow */); 369 370 /* 371 * Additional support stuff for Ed Rheingold's calendrical calculations 372 */ 373 374 /* 375 * Start day of NTP time as days past the imaginary date 12/1/1 BC. 376 * (This is the beginning of the Christian Era, or BCE.) 377 */ 378 #define DAY_NTP_STARTS 693596 379 380 /* 381 * Start day of the UNIX epoch. This is the Rata Die of 1970-01-01. 382 */ 383 #define DAY_UNIX_STARTS 719163 384 385 /* 386 * Difference between UN*X and NTP epoch (25567). 387 */ 388 #define NTP_TO_UNIX_DAYS (DAY_UNIX_STARTS - DAY_NTP_STARTS) 389 390 /* 391 * Days in a normal 4 year leap year calendar cycle (1461). 392 */ 393 #define GREGORIAN_NORMAL_LEAP_CYCLE_DAYS (3 * 365 + 366) 394 395 /* 396 * Days in a normal 100 year leap year calendar (36524). We lose a 397 * leap day in years evenly divisible by 100 but not by 400. 398 */ 399 #define GREGORIAN_NORMAL_CENTURY_DAYS \ 400 (25 * GREGORIAN_NORMAL_LEAP_CYCLE_DAYS - 1) 401 402 /* 403 * The Gregorian calendar is based on a 400 year cycle. This is the 404 * number of days in each cycle (146097). We gain a leap day in years 405 * divisible by 400 relative to the "normal" century. 406 */ 407 #define GREGORIAN_CYCLE_DAYS (4 * GREGORIAN_NORMAL_CENTURY_DAYS + 1) 408 409 /* 410 * Number of weeks in 400 years (20871). 411 */ 412 #define GREGORIAN_CYCLE_WEEKS (GREGORIAN_CYCLE_DAYS / 7) 413 414 #define is_leapyear(y) (!((y) % 4) && !(!((y) % 100) && (y) % 400)) 415 416 #endif 417