/*============================================================================= * drt/sys/ktime.h * DRT primitive date and time types and functions. * * History * 0.01, 1999-02-20, David R Tribble. * First cut. * * 0.02, 1999-03-16, David R Tribble. * Converted from C to C++. * * 1.00, 1999-04-24, David R Tribble. * Working version. * * 1.01, 1999-08-11, David R Tribble. * Added timezone functions. * Renamed struct 'drt_timezone' to 'drt_tz'. * * [Public] * Copyright ©1999, by David R. Tribble, all rights reserved. * See "drt/sys/copyr.txt" for more information. *----------------------------------------------------------------------------*/ #ifndef drt_sys_ktime_h #define drt_sys_ktime_h 101 #ifdef __cplusplus extern "C" { #endif /* Identification */ #ifndef NO_H_IDENT static const char drt_sys_ktime_h_id[] = "@(#)drt/sys/ktime.h 1.01"; #endif /* System includes */ #ifndef drt_std_time_h #include #define drt_std_time_h 1 #endif /* Special includes */ #ifndef drt_sys_kdefs_h #include "kdefs.h" #endif /* Local wrappers */ #include "klib1.h" /* Local forward declarations */ struct drt_tm; struct drt_tz; /* Public types */ /*----------------------------------------------------------------------------- * Typedef drt_time_t * Encodes an extended-precision absolute system date and time in binary * (arithmetic) form. * * Notes * This type is encoded as a 64-bit signed binary integer representing the * number of ticks since the zero date of the epoch. Leap seconds are not * encoded. The time is relative to Universal (UT) time (a.k.a. Zulu or Z * time). * * A "tick" is 100 nanoseconds (0.1 microsecond, 100 nanoseconds, 1.0e-07 * seconds) in duration. * * This encoding is capable of representing dates spanning a range of over * 58,000 years; however, only a subset of those dates are considered * valid, specifically, those dates that fall within the "proper epoch" of * this date encoding. The proper epoch contains all dates with 4-digit * year numbers in either the AD/CE or BC/BCE eras, i.e., dates within the * range BC9999 to AD9999. * * The proper epoch spans a range of 19,998 years, covering all of the * dates from: * BC9999-01-01 00:00:00.0000000 Z, Sun * to: * AD9999-12-31 23:59:59.9999999 Z, Fri * * The "zero date" (or "ZD") of the epoch is the date corresponding to a * zero time value, and is the date that occurs at the center of the * epoch, which is: * AD2001-01-01 00:00:00.0000000 Z, Mon * * Dates are thus simply the number of ticks since (or relative to) the * ZD. Dates prior to the ZD are negative time values, and dates after * the ZD are positive time values. * * This time type is capable of representing an "unknown" time, a time * that is indeterminate. Such a value always compares less than any * valid time value. It is represented as the minimum possible arithmetic * value of the time type (which is typically LLONG_MIN). * * This time type is also capable of representing a "never" time, a time * that has never (or will never) transpired. Such a value always * compares greater than any valid time value. It is represented as the * maximum possible arithmetic value of the time type (which is typically * LLONG_MAX). * * Certain time values do not represent a well-formed date and time within * the proper epoch. Such values are considered "invalid" time values. * These are time values that represent dates outside the range of the * proper epoch, such as dates with 5-digit year numbers (e.g., * AD31228-08-13). * * This time type is convertible to and from the ISO standard 'time_t' * type (which is declared in the standard header) for backward * compatibility. This type is also convertible to and from a broken-down * time type (see 'struct drt_tm' below). * * Caveats * This encoding assumes a Gregorian calendar. This does not reflect * actual historical dates in the past; e.g., most of the Catholic * European countries adopted the Gregorian calendar in 1582, most of the * English-speaking countries (including England and the USA) adopted it * in 1752, and the Orthodox Russians adopted it as late as 1918. Some * nationalities still do not use this calendar (such as some Arabic * countries). The Julian calendar was typically the calendar in use * prior to the adoption of the Gregorian calendar, and it did not * properly account for leap days in years that were multiples of 100. * In addition, New Year's Day changed in some countries; when England * adopted the Gregorian calendar, it moved that day from Mar-25 to * Jan-01. Thus dates prior to the adoption dates do not necessarily * correspond to actual historic dates. For example, the date 1700-02-29 * exists in the English (Julian) calendar because 1700 was a leap year, * but not in the French (Gregorian) calendar. Another example is George * Washington's birthday, which was 1731-02-11 in the old calendar but is * 1732-02-22 in the new Gregorian calendar. * * This means that actual historical dates do not necessarily correspond * to 'drt_time_t' dates. But it also means that 'drt_time_t' dates are * consistent across the entire 'drt_time_t' epoch. * * The Gregorian calendar is based on a 400-year cycle, i.e., the calendar * repeats every 400 years. There are 146,097 days in each 400-year * period of the Gregorian calendar (400*365 + 400/4 - 400/100 + 400/400 * days, or 146,000 days plus 97 leap days), and each day has 86,400 * seconds (24 hours of 60*60 seconds), which means there are exactly * 31,556,952 seconds in a year (365.2425 days, or 365 days plus 05:49:12 * hours). Thus there are exactly 315,569,520,000,000 ticks in a standard * Gregorian year. * * Note that year number +1 is AD0001, and year number +0 is BC0001; there * is no year AD0000 or BC0000. Note also that BC9999 is year number * -9998; year number -9999 does not represent a valid date in the proper * epoch (because it would represent the year BC10000, which has more than * four digits). * * Leap seconds are not accounted for in this encoding. This is mainly * due to the fact that it is impossible to predict when future leap * seconds will occur, so properly adjusting for future time values is * simply not possible. (Note that the first leap second occurred on * 1972-06-30, and that leap seconds tend to be added about once every * 500 days, because the Earth is slow in its rotation by about 2 msec per * day; most leap seconds occur on 23:59:60 on Dec-31 or Jun-30.) * * Some potentially valid timezone-adjusted dates are not considered * valid date values, e.g., AD9999-12-31 23:59:59 in any timezone to the * West of Z (UT), and BC9999-01-01 00:00:00 in any timezone to the East * of Z (UT). Such times occur only within two 23-hour time periods at * the very beginning and the very end of the proper epoch, though, so * this should not be considered a problem. * * Converting a value of this time type into a value of 'time_t' type may * result in truncation (i.e., underflow or overflow); this is a * consequence of the fact that this type can usually represent a wider * range of dates than the 'time_t' type can. On the other hand, * converting a 'time_t' value to this type may result in overflow, since * large 'time_t' types (such as 64-bit 'signed long long int') could * contain dates far outside the range of valid dates for this type. * * Comparisons of time values abide by the following truth table, where * '?' indicates an indeterminate ordering: * * | Left operand * Right | unknown valid never invalid * --------+--------------------------------- * unknown | = < < < * valid | > <,=,> < ? * never | > > = > * invalid | > ? < ? * * History * 100, 1999-03-16, David R Tribble. * First cut. *----------------------------------------------------------------------------*/ #define DRT_TIME_VS 100 /* Typedef version number */ typedef drt_int64_t drt_time_t; /* Extended time type */ /* Public constants */ extern const int drt_time_vs; /* Typedef version number */ extern const long int DRT_TIME_TICKS_PER_SEC; /* Number of ticks in a second */ extern const drt_int64_t DRT_TIME_TICKS_PER_DAY; /* Number of ticks in a day */ extern const drt_int64_t DRT_TIME_TICKS_PER_YEAR; /* Number of ticks in a year */ extern const drt_time_t DRT_TIME_UNKNOWN; /* Unknown time */ extern const drt_time_t DRT_TIME_NEVER; /* Never time */ extern const drt_time_t DRT_TIME_MIN; /* BC9999-01-01 00:00:00.000 Z */ extern const drt_time_t DRT_TIME_MAX; /* AD9999-12-31 23:59:59.999 Z */ extern const int DRT_TIME_ZYEAR; /* Zero year of the epoch */ /* Public functions */ extern bool DRTFUNC drt_time_now(drt_time_t *th); /* Get the current system time */ extern bool DRTFUNC drt_time_is_valid(drt_time_t th); /* Is a valid time */ extern bool DRTFUNC drt_time_is_unknown(drt_time_t th); /* Is unknown */ extern bool DRTFUNC drt_time_is_never(drt_time_t th); /* Is never */ extern bool DRTFUNC drt_time_setconv(drt_time_t *th, time_t t); /* Convert time */ extern bool DRTFUNC drt_time_conv(time_t *t, drt_time_t th); /* Convert time */ extern bool DRTFUNC drt_time_gmtime(struct drt_tm *th, drt_time_t t); /* Get the UT time value */ extern bool DRTFUNC drt_time_make(drt_time_t *th, struct drt_tm *t); /* Normalize & convert time */ extern bool DRTFUNC drt_time_adjtz(drt_time_t *th, const struct drt_tz *tz); /* Adjust time for a timezone */ extern int DRTFUNC drt_time_cmp(const drt_time_t *a, const drt_time_t *b); /* Compare times */ extern int DRTFUNC drt_time_to_string(const drt_time_t th, char *buf, size_t len);/* Convert to a string */ extern int DRTFUNC drt_time_from_string(const char *buf, drt_time_t *th); /* Convert from a string */ extern bool DRTFUNC drt_time_is_leap(long yr); /* Check for a leap year */ /*----------------------------------------------------------------------------- * Struct drt_tm * Representation of a date/time in a broken-down form. * Used to represent a full date and time. Also used to represent a delta * time (i.e., the difference between two date/times). * * An object of this class type contains the following components of a * given date and time: * year [-9 998, +9 999], zero is 1 BC/BCE * month [0, 11], zero is Jan * week [0, 52] * day [1, 31] * yearday [0, 365], zero is Jan 01 * weekday [0, 6], zero is Sun * hour [0, 23] * minute [0, 59] * second [0, 60], can be a leap second * nanosecond [0, 999 999 999] * * An object of this class type can be set to an "unknown" date/time * (which represents an unknown time, and which compares less than any * known time), or to a "never" time (which represents a time that has * never occurred, and which compares greater than any known time). * Extracting the components of an "unknown" or "never" time, or * converting such a value into a string, results in meaningless values. * * History * 100, 1999-03-14, David R Tribble. * First cut. * * 101, 1999-03-21, David R Tribble. * Changed .tm_usec (microseconds) to .tm_nsec (nanoseconds). *----------------------------------------------------------------------------*/ #define DRT_TM_VS 101 /* Struct version number */ struct drt_tm { int tm_vers; /* Struct version */ int tm_year; /* Year, [-9998,+9999] */ int tm_mon; /* Months since Jan, [0,11] */ int tm_mday; /* Day of month, [1,31] */ int tm_hour; /* Hour, [0,23] */ int tm_min; /* Minute, [0,59] */ int tm_sec; /* Second, [0,59] */ long int tm_nsec; /* Nanoseconds, [0,999999999] */ int tm_yday; /* Days since Jan-01, [0,365] */ int tm_wday; /* Weekdays since Sun, [0,6] */ /* int tm_week; /* Week of the year, [0,52] */ /* int tm_dst; /* DST minutes West of UT */ }; /* Public constants */ extern const int drt_tm_VS; /* Struct version number */ extern const char drt_tm_iso8601[]; /* Default ISO-8601 format */ extern const char drt_tm_month[12][3+1]; /* Default month names */ extern const char drt_tm_wkday[7][3+1]; /* Default weekday names */ /* Public functions */ extern bool DRTFUNC drt_tm_validate(const struct drt_tm *th); /* Validate a date struct */ extern bool DRTFUNC drt_tm_zero(struct drt_tm *th); /* Initialize a date to ZD */ extern bool DRTFUNC drt_tm_unknown(struct drt_tm *th); /* Get an unknown date */ extern bool DRTFUNC drt_tm_never(struct drt_tm *th); /* Get a never date */ extern bool DRTFUNC drt_tm_gmtime(struct drt_tm *th, drt_time_t t); /* Get the UT time value */ extern bool DRTFUNC drt_tm_gmconv(struct drt_tm *th, const struct tm *t); /* Get the UT time value */ extern bool DRTFUNC drt_tm_make(const struct drt_tm *th, drt_time_t *t); /* Convert time */ extern bool DRTFUNC drt_tm_localtime(struct drt_tm *th, drt_time_t t); /* Get the local time value */ extern bool DRTFUNC drt_tm_localconv(struct drt_tm *th, const struct tm *t); /* Get the local time value */ extern bool DRTFUNC drt_tm_localtime_tz(struct drt_tm *th, drt_time_t t, const struct drt_tz *tz); /* Get a local time value */ extern bool DRTFUNC drt_tm_adjtz(struct drt_tm *th, const struct drt_tz *tz); /* Adjust time for a timezone */ extern bool DRTFUNC drt_tm_set_unknown(struct drt_tm *th); /* Set to unknown */ extern bool DRTFUNC drt_tm_set_never(struct drt_tm *th); /* Set to never */ extern bool DRTFUNC drt_tm_normalize(struct drt_tm *th); /* Normalize the members */ extern bool DRTFUNC drt_tm_is_valid(const struct drt_tm *th); /* Is a valid date */ extern bool DRTFUNC drt_tm_is_unknown(const struct drt_tm *th); /* Is unknown */ extern bool DRTFUNC drt_tm_is_never(const struct drt_tm *th); /* Is never */ extern bool DRTFUNC drt_tm_is_leap(const struct drt_tm *th); /* Is a leap year */ extern bool DRTFUNC drt_tm_add_year(struct drt_tm *th, int v); /* Add years */ extern bool DRTFUNC drt_tm_add_month(struct drt_tm *th, int v); /* Add months */ extern bool DRTFUNC drt_tm_add_week(struct drt_tm *th, int v); /* Add weeks */ extern bool DRTFUNC drt_tm_add_day(struct drt_tm *th, int v); /* Add days */ extern bool DRTFUNC drt_tm_add_hour(struct drt_tm *th, int v); /* Add hours */ extern bool DRTFUNC drt_tm_add_min(struct drt_tm *th, int v); /* Add minutes */ extern bool DRTFUNC drt_tm_add_sec(struct drt_tm *th, int v); /* Add seconds */ extern bool DRTFUNC drt_tm_add_nsec(struct drt_tm *th, long int v); /* Add nanoseconds */ extern bool DRTFUNC drt_tm_add(struct drt_tm *th, const struct drt_tm *r); /* Add a delta time */ extern bool DRTFUNC drt_tm_diff(struct drt_tm *th, const struct drt_tm *a, const struct drt_tm *b); /* Compute a delta time */ extern int DRTFUNC drt_tm_strf(const struct drt_tm *th, const char *fmt, char *buf, size_t len); /* Convert to formatted string */ extern bool DRTFUNC drt_tm_conv(drt_time_t *t, const struct drt_tm *th); /* Convert the time */ extern int DRTFUNC drt_tm_cmp(const struct drt_tm *a, const struct drt_tm *b); /* Compare times */ extern int DRTFUNC drt_tm_yday(const struct drt_tm *th); /* Default the day of the year */ extern int DRTFUNC drt_tm_wday(const struct drt_tm *th); /* Default the day of the week */ /*----------------------------------------------------------------------------- * Struct drt_tz * Time zone value. * Represents a timezone setting, encoding its offset (HH:MM:SS) from the * UTC (Zulu) timezone. * * History * 100, 1999-03-16, David R Tribble. * First cut. * * 101, 1999-08-12, David R Tribble. * Added 'tz_vers' member. *----------------------------------------------------------------------------*/ #define DRT_TZ_VS 101 /* Struct version number */ struct drt_tz { int tz_vers; /* Struct version number */ int tz_hour; /* Hours West of GMT */ int tz_min; /* Minutes West of GMT */ int tz_sec; /* Seconds West of GMT */ int tz_dst; /* DST in effect */ char tz_name[15+1]; /* Name, "CST6CDT" format */ }; /* Public constants */ extern const int drt_tz_VS; /* Struct version number */ /* Public functions */ extern bool DRTFUNC drt_tz_validate(const struct drt_tz *th); /* Validate a timezone struct */ extern bool DRTFUNC drt_tz_zero(struct drt_tz *th); /* Set timezone to Zulu (Z, UT) */ extern bool DRTFUNC drt_tz_local(struct drt_tz *th); /* Determine the local timezone */ extern bool DRTFUNC drt_tz_find(struct drt_tz *th, const char *n); /* Find timezone info by name */ extern int DRTFUNC drt_tz_to_string(const struct drt_tz *th, char *buf, size_t len); /* Convert to a string */ extern int DRTFUNC drt_tz_from_string(struct drt_tz *th, const char *buf); /* Convert from a string */ extern int DRTFUNC drt_tz_diff(struct drt_tz *th, const struct drt_tz *a, const struct drt_tz *b); /* Find difference in TZs */ /* Wrapper end */ #include "klib2.h" #ifdef __cplusplus } #endif #endif /* drt_sys_ktime_h */ /* End ktime.h */