2d4e511ca2
Update ntp-4.2.8p13 --> 4.2.8p14. The advisory can be found at: http://support.ntp.org/bin/view/Main/SecurityNotice#\ March_2020_ntp_4_2_8p14_NTP_Rele No CVEs have been documented yet. MFC after: now Security: http://support.ntp.org/bin/view/Main/NtpBug3610 http://support.ntp.org/bin/view/Main/NtpBug3596 http://support.ntp.org/bin/view/Main/NtpBug3592
542 lines
15 KiB
C
542 lines
15 KiB
C
/*
|
|
* ntp_calendar.h - definitions for the calendar time-of-day routine
|
|
*/
|
|
#ifndef NTP_CALENDAR_H
|
|
#define NTP_CALENDAR_H
|
|
|
|
#include <time.h>
|
|
|
|
#include "ntp_types.h"
|
|
|
|
/* gregorian calendar date */
|
|
struct calendar {
|
|
uint16_t year; /* year (A.D.) */
|
|
uint16_t yearday; /* day of year, 1 = January 1 */
|
|
uint8_t month; /* month, 1 = January */
|
|
uint8_t monthday; /* day of month */
|
|
uint8_t hour; /* hour of day, midnight = 0 */
|
|
uint8_t minute; /* minute of hour */
|
|
uint8_t second; /* second of minute */
|
|
uint8_t weekday; /* 0..7, 0=Sunday */
|
|
};
|
|
typedef struct calendar TCivilDate;
|
|
typedef struct calendar const TcCivilDate;
|
|
|
|
/* ISO week calendar date */
|
|
struct isodate {
|
|
uint16_t year; /* year (A.D.) */
|
|
uint8_t week; /* 1..53, week in year */
|
|
uint8_t weekday; /* 1..7, 1=Monday */
|
|
uint8_t hour; /* hour of day, midnight = 0 */
|
|
uint8_t minute; /* minute of hour */
|
|
uint8_t second; /* second of minute */
|
|
};
|
|
typedef struct isodate TIsoDate;
|
|
typedef struct isodate const TcIsoDate;
|
|
|
|
/* general split representation */
|
|
typedef struct {
|
|
int32_t hi;
|
|
int32_t lo;
|
|
} ntpcal_split;
|
|
|
|
typedef time_t (*systime_func_ptr)(time_t *);
|
|
|
|
/*
|
|
* set the function for getting the system time. This is mostly used for
|
|
* unit testing to provide a fixed / shifted time stamp. Setting the
|
|
* value to NULL restores the original function, that is, 'time()',
|
|
* which is also the automatic default.
|
|
*/
|
|
extern systime_func_ptr ntpcal_set_timefunc(systime_func_ptr);
|
|
|
|
/*
|
|
* days-of-week
|
|
*/
|
|
#define CAL_SUNDAY 0
|
|
#define CAL_MONDAY 1
|
|
#define CAL_TUESDAY 2
|
|
#define CAL_WEDNESDAY 3
|
|
#define CAL_THURSDAY 4
|
|
#define CAL_FRIDAY 5
|
|
#define CAL_SATURDAY 6
|
|
#define CAL_SUNDAY7 7 /* also sunday */
|
|
|
|
/*
|
|
* Days in each month. 30 days hath September...
|
|
*/
|
|
#define JAN 31
|
|
#define FEB 28
|
|
#define FEBLEAP 29
|
|
#define MAR 31
|
|
#define APR 30
|
|
#define MAY 31
|
|
#define JUN 30
|
|
#define JUL 31
|
|
#define AUG 31
|
|
#define SEP 30
|
|
#define OCT 31
|
|
#define NOV 30
|
|
#define DEC 31
|
|
|
|
/*
|
|
* We deal in a 4 year cycle starting at March 1, 1900. We assume
|
|
* we will only want to deal with dates since then, and not to exceed
|
|
* the rollover day in 2036.
|
|
*/
|
|
#define SECSPERMIN (60) /* seconds per minute */
|
|
#define MINSPERHR (60) /* minutes per hour */
|
|
#define HRSPERDAY (24) /* hours per day */
|
|
#define DAYSPERWEEK (7) /* days per week */
|
|
#define DAYSPERYEAR (365) /* days per year */
|
|
|
|
#define SECSPERHR (SECSPERMIN * MINSPERHR)
|
|
#define SECSPERDAY (SECSPERHR * HRSPERDAY)
|
|
#define SECSPERWEEK (DAYSPERWEEK * SECSPERDAY)
|
|
#define SECSPERYEAR (365 * SECSPERDAY) /* regular year */
|
|
#define SECSPERLEAPYEAR (366 * SECSPERDAY) /* leap year */
|
|
#define SECSPERAVGYEAR 31556952 /* mean year length over 400yrs */
|
|
|
|
#define GPSWEEKS 1024 /* GPS week cycle */
|
|
/*
|
|
* Gross hacks. I have illicit knowlege that there won't be overflows
|
|
* here, the compiler often can't tell this.
|
|
*/
|
|
#define TIMES60(val) ((((val)<<4) - (val))<<2) /* *(16 - 1) * 4 */
|
|
#define TIMES24(val) (((val)<<4) + ((val)<<3)) /* *16 + *8 */
|
|
#define TIMES7(val) (((val)<<3) - (val)) /* *8 - *1 */
|
|
#define TIMESDPERC(val) (((val)<<10) + ((val)<<8) \
|
|
+ ((val)<<7) + ((val)<<5) \
|
|
+ ((val)<<4) + ((val)<<2) + (val)) /* *big* hack */
|
|
|
|
|
|
extern const char * const months[12];
|
|
extern const char * const daynames[7];
|
|
|
|
extern char * ntpcal_iso8601std(char*, size_t, struct calendar const*);
|
|
extern void caljulian (uint32_t, struct calendar *);
|
|
extern uint32_t caltontp (const struct calendar *);
|
|
|
|
/*
|
|
* Convert between 'time_t' and 'vint64'
|
|
*/
|
|
extern vint64 time_to_vint64(const time_t *);
|
|
extern time_t vint64_to_time(const vint64 *);
|
|
|
|
/*
|
|
* Get the build date & time. ATTENTION: The time zone is not specified!
|
|
* This depends entirely on the C compilers' capabilities to properly
|
|
* expand the '__TIME__' and '__DATE__' macros, as required by the C
|
|
* standard.
|
|
*/
|
|
extern int
|
|
ntpcal_get_build_date(struct calendar * /* jd */);
|
|
|
|
/*
|
|
* Convert a timestamp in NTP scale to a time_t value in the UN*X
|
|
* scale with proper epoch unfolding around a given pivot or the
|
|
* current system time.
|
|
*/
|
|
extern vint64
|
|
ntpcal_ntp_to_time(uint32_t /* ntp */, const time_t * /* pivot */);
|
|
|
|
/*
|
|
* Convert a timestamp in NTP scale to a 64bit seconds value in the NTP
|
|
* scale with proper epoch unfolding around a given pivot or the current
|
|
* system time.
|
|
* Note: The pivot must be given in UN*X time scale!
|
|
*/
|
|
extern vint64
|
|
ntpcal_ntp_to_ntp(uint32_t /* ntp */, const time_t * /* pivot */);
|
|
|
|
/*
|
|
* Split a time stamp in seconds into elapsed days and elapsed seconds
|
|
* since midnight.
|
|
*/
|
|
extern ntpcal_split
|
|
ntpcal_daysplit(const vint64 *);
|
|
|
|
/*
|
|
* Split a time stamp in seconds into elapsed weeks and elapsed seconds
|
|
* since start of week.
|
|
*/
|
|
extern ntpcal_split
|
|
ntpcal_weeksplit(const vint64 *);
|
|
|
|
/*
|
|
* Merge a number of days and a number of seconds into seconds,
|
|
* expressed in 64 bits to avoid overflow.
|
|
*/
|
|
extern vint64
|
|
ntpcal_dayjoin(int32_t /* days */, int32_t /* seconds */);
|
|
|
|
/*
|
|
* Merge a number of weeks and a number of seconds into seconds,
|
|
* expressed in 64 bits to avoid overflow.
|
|
*/
|
|
extern vint64
|
|
ntpcal_weekjoin(int32_t /* weeks */, int32_t /* seconds */);
|
|
|
|
/* Get the number of leap years since epoch for the number of elapsed
|
|
* full years
|
|
*/
|
|
extern int32_t
|
|
ntpcal_leapyears_in_years(int32_t /* years */);
|
|
|
|
/*
|
|
* Convert elapsed years in Era into elapsed days in Era.
|
|
*/
|
|
extern int32_t
|
|
ntpcal_days_in_years(int32_t /* years */);
|
|
|
|
/*
|
|
* Convert a number of elapsed month in a year into elapsed days
|
|
* in year.
|
|
*
|
|
* The month will be normalized, and 'res.hi' will contain the
|
|
* excessive years that must be considered when converting the years,
|
|
* while 'res.lo' will contain the days since start of the
|
|
* year. (Expect the resulting days to be negative, with a positive
|
|
* excess! But then, we need no leap year flag, either...)
|
|
*/
|
|
extern ntpcal_split
|
|
ntpcal_days_in_months(int32_t /* months */);
|
|
|
|
/*
|
|
* Convert ELAPSED years/months/days of gregorian calendar to elapsed
|
|
* days in Gregorian epoch. No range checks done here!
|
|
*/
|
|
extern int32_t
|
|
ntpcal_edate_to_eradays(int32_t /* years */, int32_t /* months */, int32_t /* mdays */);
|
|
|
|
/*
|
|
* Convert a time spec to seconds. No range checks done here!
|
|
*/
|
|
extern int32_t
|
|
ntpcal_etime_to_seconds(int32_t /* hours */, int32_t /* minutes */, int32_t /* seconds */);
|
|
|
|
/*
|
|
* Convert ELAPSED years/months/days of gregorian calendar to elapsed
|
|
* days in year.
|
|
*
|
|
* Note: This will give the true difference to the start of the given year,
|
|
* even if months & days are off-scale.
|
|
*/
|
|
extern int32_t
|
|
ntpcal_edate_to_yeardays(int32_t /* years */, int32_t /* months */, int32_t /* mdays */);
|
|
|
|
/*
|
|
* Convert the date part of a 'struct tm' (that is, year, month,
|
|
* day-of-month) into the RataDie of that day.
|
|
*/
|
|
extern int32_t
|
|
ntpcal_tm_to_rd(const struct tm * /* utm */);
|
|
|
|
/*
|
|
* Convert the date part of a 'struct calendar' (that is, year, month,
|
|
* day-of-month) into the RataDie of that day.
|
|
*/
|
|
extern int32_t
|
|
ntpcal_date_to_rd(const struct calendar * /* jt */);
|
|
|
|
/*
|
|
* Given the number of elapsed days in the calendar era, split this
|
|
* number into the number of elapsed years in 'res.quot' and the
|
|
* number of elapsed days of that year in 'res.rem'.
|
|
*
|
|
* if 'isleapyear' is not NULL, it will receive an integer that is 0
|
|
* for regular years and a non-zero value for leap years.
|
|
*
|
|
* The input is limited to [-2^30, 2^30-1]. If the days exceed this
|
|
* range, errno is set to EDOM and the result is saturated.
|
|
*/
|
|
extern ntpcal_split
|
|
ntpcal_split_eradays(int32_t /* days */, int/*BOOL*/ * /* isleapyear */);
|
|
|
|
/*
|
|
* Given a number of elapsed days in a year and a leap year indicator,
|
|
* split the number of elapsed days into the number of elapsed months
|
|
* in 'res.quot' and the number of elapsed days of that month in
|
|
* 'res.rem'.
|
|
*/
|
|
extern ntpcal_split
|
|
ntpcal_split_yeardays(int32_t /* eyd */, int/*BOOL*/ /* isleapyear */);
|
|
|
|
/*
|
|
* Convert a RataDie number into the date part of a 'struct
|
|
* calendar'. Return 0 if the year is regular year, !0 if the year is
|
|
* a leap year.
|
|
*/
|
|
extern int/*BOOL*/
|
|
ntpcal_rd_to_date(struct calendar * /* jt */, int32_t /* rd */);
|
|
|
|
/*
|
|
* Convert a RataDie number into the date part of a 'struct
|
|
* tm'. Return 0 if the year is regular year, !0 if the year is a leap
|
|
* year.
|
|
*/
|
|
extern int/*BOOL*/
|
|
ntpcal_rd_to_tm(struct tm * /* utm */, int32_t /* rd */);
|
|
|
|
/*
|
|
* Take a value of seconds since midnight and split it into hhmmss in
|
|
* a 'struct calendar'. Return excessive days.
|
|
*/
|
|
extern int32_t
|
|
ntpcal_daysec_to_date(struct calendar * /* jt */, int32_t /* secs */);
|
|
|
|
/*
|
|
* Take the time part of a 'struct calendar' and return the seconds
|
|
* since midnight.
|
|
*/
|
|
extern int32_t
|
|
ntpcal_date_to_daysec(const struct calendar *);
|
|
|
|
/*
|
|
* Take a value of seconds since midnight and split it into hhmmss in
|
|
* a 'struct tm'. Return excessive days.
|
|
*/
|
|
extern int32_t
|
|
ntpcal_daysec_to_tm(struct tm * /* utm */, int32_t /* secs */);
|
|
|
|
extern int32_t
|
|
ntpcal_tm_to_daysec(const struct tm * /* utm */);
|
|
|
|
/*
|
|
* convert a year number to rata die of year start
|
|
*/
|
|
extern int32_t
|
|
ntpcal_year_to_ystart(int32_t /* year */);
|
|
|
|
/*
|
|
* For a given RataDie, get the RataDie of the associated year start,
|
|
* that is, the RataDie of the last January,1st on or before that day.
|
|
*/
|
|
extern int32_t
|
|
ntpcal_rd_to_ystart(int32_t /* rd */);
|
|
|
|
/*
|
|
* convert a RataDie to the RataDie of start of the calendar month.
|
|
*/
|
|
extern int32_t
|
|
ntpcal_rd_to_mstart(int32_t /* year */);
|
|
|
|
|
|
extern int
|
|
ntpcal_daysplit_to_date(struct calendar * /* jt */,
|
|
const ntpcal_split * /* ds */, int32_t /* dof */);
|
|
|
|
extern int
|
|
ntpcal_daysplit_to_tm(struct tm * /* utm */, const ntpcal_split * /* ds */,
|
|
int32_t /* dof */);
|
|
|
|
extern int
|
|
ntpcal_time_to_date(struct calendar * /* jd */, const vint64 * /* ts */);
|
|
|
|
extern int32_t
|
|
ntpcal_periodic_extend(int32_t /* pivot */, int32_t /* value */,
|
|
int32_t /* cycle */);
|
|
|
|
extern int
|
|
ntpcal_ntp64_to_date(struct calendar * /* jd */, const vint64 * /* ntp */);
|
|
|
|
extern int
|
|
ntpcal_ntp_to_date(struct calendar * /* jd */, uint32_t /* ntp */,
|
|
const time_t * /* pivot */);
|
|
|
|
extern vint64
|
|
ntpcal_date_to_ntp64(const struct calendar * /* jd */);
|
|
|
|
extern uint32_t
|
|
ntpcal_date_to_ntp(const struct calendar * /* jd */);
|
|
|
|
extern time_t
|
|
ntpcal_date_to_time(const struct calendar * /* jd */);
|
|
|
|
/*
|
|
* ISO week-calendar conversions
|
|
*/
|
|
extern int32_t
|
|
isocal_weeks_in_years(int32_t /* years */);
|
|
|
|
/*
|
|
* The input is limited to [-2^30, 2^30-1]. If the weeks exceed this
|
|
* range, errno is set to EDOM and the result is saturated.
|
|
*/
|
|
extern ntpcal_split
|
|
isocal_split_eraweeks(int32_t /* weeks */);
|
|
|
|
extern int
|
|
isocal_ntp64_to_date(struct isodate * /* id */, const vint64 * /* ntp */);
|
|
|
|
extern int
|
|
isocal_ntp_to_date(struct isodate * /* id */, uint32_t /* ntp */,
|
|
const time_t * /* pivot */);
|
|
|
|
extern vint64
|
|
isocal_date_to_ntp64(const struct isodate * /* id */);
|
|
|
|
extern uint32_t
|
|
isocal_date_to_ntp(const struct isodate * /* id */);
|
|
|
|
|
|
/*
|
|
* day-of-week calculations
|
|
*
|
|
* Given a RataDie and a day-of-week, calculate a RDN that is reater-than,
|
|
* greater-or equal, closest, less-or-equal or less-than the given RDN
|
|
* and denotes the given day-of-week
|
|
*/
|
|
extern int32_t
|
|
ntpcal_weekday_gt(int32_t /* rdn */, int32_t /* dow */);
|
|
|
|
extern int32_t
|
|
ntpcal_weekday_ge(int32_t /* rdn */, int32_t /* dow */);
|
|
|
|
extern int32_t
|
|
ntpcal_weekday_close(int32_t /* rdn */, int32_t /* dow */);
|
|
|
|
extern int32_t
|
|
ntpcal_weekday_le(int32_t /* rdn */, int32_t /* dow */);
|
|
|
|
extern int32_t
|
|
ntpcal_weekday_lt(int32_t /* rdn */, int32_t /* dow */);
|
|
|
|
|
|
/*
|
|
* handling of base date spec
|
|
*/
|
|
extern int32_t
|
|
basedate_eval_buildstamp(void);
|
|
|
|
extern int32_t
|
|
basedate_eval_string(const char *str);
|
|
|
|
extern int32_t
|
|
basedate_set_day(int32_t dayno);
|
|
|
|
extern uint32_t
|
|
basedate_get_day(void);
|
|
|
|
extern time_t
|
|
basedate_get_eracenter(void);
|
|
|
|
extern time_t
|
|
basedate_get_erabase(void);
|
|
|
|
extern uint32_t
|
|
basedate_get_gpsweek(void);
|
|
|
|
extern uint32_t
|
|
basedate_expand_gpsweek(unsigned short weekno);
|
|
|
|
/*
|
|
* Additional support stuff for Ed Rheingold's calendrical calculations
|
|
*/
|
|
|
|
/*
|
|
* Start day of NTP time as days past 0000-12-31 in the proleptic
|
|
* Gregorian calendar. (So 0001-01-01 is day number 1; this is the Rata
|
|
* Die counting scheme used by Ed Rheingold in his book "Calendrical
|
|
* Calculations".)
|
|
*/
|
|
#define DAY_NTP_STARTS 693596
|
|
|
|
/*
|
|
* Start day of the UNIX epoch. This is the Rata Die of 1970-01-01.
|
|
*/
|
|
#define DAY_UNIX_STARTS 719163
|
|
|
|
/*
|
|
* Start day of the GPS epoch. This is the Rata Die of 1980-01-06
|
|
*/
|
|
#define DAY_GPS_STARTS 722820
|
|
|
|
/*
|
|
* Difference between UN*X and NTP epoch (25567).
|
|
*/
|
|
#define NTP_TO_UNIX_DAYS (DAY_UNIX_STARTS - DAY_NTP_STARTS)
|
|
|
|
/*
|
|
* Difference between GPS and NTP epoch (29224)
|
|
*/
|
|
#define NTP_TO_GPS_DAYS (DAY_GPS_STARTS - DAY_NTP_STARTS)
|
|
|
|
/*
|
|
* Days in a normal 4 year leap year calendar cycle (1461).
|
|
*/
|
|
#define GREGORIAN_NORMAL_LEAP_CYCLE_DAYS (4 * 365 + 1)
|
|
|
|
/*
|
|
* Days in a normal 100 year leap year calendar (36524). We lose a
|
|
* leap day in years evenly divisible by 100 but not by 400.
|
|
*/
|
|
#define GREGORIAN_NORMAL_CENTURY_DAYS \
|
|
(25 * GREGORIAN_NORMAL_LEAP_CYCLE_DAYS - 1)
|
|
|
|
/*
|
|
* The Gregorian calendar is based on a 400 year cycle. This is the
|
|
* number of days in each cycle (146097). We gain a leap day in years
|
|
* divisible by 400 relative to the "normal" century.
|
|
*/
|
|
#define GREGORIAN_CYCLE_DAYS (4 * GREGORIAN_NORMAL_CENTURY_DAYS + 1)
|
|
|
|
/*
|
|
* Number of weeks in 400 years (20871).
|
|
*/
|
|
#define GREGORIAN_CYCLE_WEEKS (GREGORIAN_CYCLE_DAYS / 7)
|
|
|
|
/*
|
|
* Is a Greogorian calendar year a leap year? The obvious solution is to
|
|
* test the expression
|
|
*
|
|
* (y % 4 == 0) && ((y % 100 != 0) || (y % 400 == 0))
|
|
*
|
|
* This needs (in theory) 2 true divisions -- most compilers check the
|
|
* (mod 4) condition by doing a bit test. Some compilers have been
|
|
* even observed to partially fuse the (mod 100) and (mod 400) test,
|
|
* but there is an alternative formula that gives the compiler even
|
|
* better chances:
|
|
*
|
|
* (y % 4 == 0) && ((y % 16 == 0) || (y % 25 != 0))
|
|
*
|
|
* The order of checks is chosen so that the shorcut evaluation can fix
|
|
* the result as soon as possible. And the compiler has to do only one
|
|
* true division here -- the (mod 4) and (mod 16) can be done with
|
|
* direct bit tests. *If* the compiler chooses to do so.
|
|
*
|
|
* The deduction is as follows: rewrite the standard formula as
|
|
* (y % 4 == 0) && ((y % 4*25 != 0) || (y % 16*25 == 0))
|
|
*
|
|
* then split the congruences:
|
|
* (y % 4 == 0) && ((y % 4 != 0 || y % 25 != 0) || (y % 16 == 0 && y % 25 == 0))
|
|
*
|
|
* eliminate the 1st inner term, as it is provably false:
|
|
* (y % 4 == 0) && (y % 25 != 0 || (y % 16 == 0 && y % 25 == 0))
|
|
*
|
|
* Use the distributive laws on the second major group:
|
|
* (y % 4 == 0) && ((y % 25 != 0 || y % 16 == 0) && (y % 25 != 0 || y % 25 == 0))
|
|
*
|
|
* Eliminate the constant term, reorder, and voila:
|
|
*/
|
|
|
|
static inline int
|
|
is_leapyear(int32_t y) {
|
|
return !(y % 4) && (!(y % 16) || (y % 25));
|
|
}
|
|
/* The (mod 4) test eliminates 3/4 (or 12/16) of all values.
|
|
* The (mod 16) test eliminates another 1/16 of all values.
|
|
* 3/16 of all values reach the final division.
|
|
* Assuming that the true division is the most costly operation, this
|
|
* sequence should give most bang for the buck.
|
|
*/
|
|
|
|
/* misc */
|
|
extern int u32mod7(uint32_t x);
|
|
extern int i32mod7(int32_t x);
|
|
extern uint32_t i32fmod(int32_t x, uint32_t d);
|
|
|
|
extern int32_t ntpcal_expand_century(uint32_t y, uint32_t m, uint32_t d, uint32_t wd);
|
|
|
|
#endif
|