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