MIRDATE(3) BSD Programmer's Manual MIRDATE(3)
mirtime_daylength, mirtime_getleaps, mirtime_isleap, timet2posix, posix2timet, timet2mjd, mjd2timet, timet2tm, tm2timet, mjd_explode, mjd_implode - MirBSD time API
int mirtime_daylength(time_t mjdday); // mjdday must be in [MJD_MIN; MJD_MAX] const time_t * mirtime_getleaps(void); int mirtime_isleap(time_t t); time_t timet2posix(time_t t); time_t posix2timet(time_t t); // t must be in [TIME_MIN; TIMET_POSIX_MAX] mirtime_mjd * timet2mjd(mirtime_mjd *mjd, time_t t); time_t mjd2timet(mirtime_mjd *mjd); // mjd->mjd must be in [MJD_MIN; MJD_MAX] or see below // mjd->sec must be in [0; 86399] or 86400 if leap struct tm * timet2tm(struct tm *dst, time_t src); time_t tm2timet(struct tm *src); // constraints tbd struct tm * mjd_explode(struct tm *tm, mirtime_mjd *mjd); mirtime_mjd * mjd_implode(mirtime_mjd *mjd, struct tm *tm); // constraints tbd
The mirtime_daylength() function returns the length of mjdday in seconds (86400 or, if leap, 86401) or 0 (if the argument was out of bounds). The mirtime_getleaps() function returns a pointer (which is guaranteed to be not NULL) to a read-only array of time_t values that are positive leap seconds, terminated by a value of 0. These functions use a table which should be initialised with tzset() before using chroot(2) or a similar mechanism. The mirtime_isleap() function returns 1 if t is known to be a leap second, 0 otherwise. Both use the leap second-aware time_t scale. The remaining functions mentioned convert time values between a broken- down calendar date struct tm, a Modified Julian Date mirtime_mjd, seconds since the First of January, 1970, midnight UTC time_t, and POSIX time (seconds since the epoch, 86400 seconds per day, also stored in time_t). mjd_implode() and tm2timet() parse the fields tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_gmtoff of struct tm; mjd_explode() and timet2tm() fill in the fields tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday, tm_yday with sensible values and tm_isdst, tm_gmtoff, tm_zone with nil values. Use these functions, macros and types on MirBSD by including <sys/time.h> and/or <time.h> under _ALL_SOURCE; test for SYSKERN_MIRTIME_H.
time_t is a signed integral type of 32 or 64 bit, machine-dependent. Currently, it is signed long long on all MirBSD platforms. Other systems may have different-sized, unsigned, or even floating point(!) time_t. struct tm consists of the following slots: int tm_sec; /* seconds [0-60] */ int tm_min; /* minutes [0-59] */ int tm_hour; /* hours [0-23] */ int tm_mday; /* day of month [1-31] */ int tm_mon; /* month of year - 1 [0-11] */ int tm_year; /* years since 1900 */ int tm_wday; /* day of week [0-6] (0=Sunday) OUT */ int tm_yday; /* day of year [0-365] OUT */ int tm_isdst; /* summer time? [<0 unknown, 0 no, >0 yes] */ long tm_gmtoff; /* seconds offset from UTC to the east */ char *tm_zone; /* abbreviation of timezone name OUT */ mirtime_mjd consists of the following slots: time_t mjd; /* days since 1858-11-17, JD 2'400'000.5 */ int sec; /* (UTC) seconds into that day [0-86400] */ Functions are not required to handle out-of-bounds sec because 86400 is special; mirtime_mjd must thus be normalised on pain of UB. One function historically permitted unsafe out-of-range sec values but no longer does. mjd must be an integral number even if time_t is a floating point type.
You can calculate safe values with the following formulae: TIMET_POSIX_MAX = timet2posix(TIME_MAX) MJD_MAX = (timet2posix(TIME_MAX - 1) - 86399) / 86400 + 40587 MJD_MIN = TIME_MIN / 86400 + 40587 Note that TIME_MAX and TIME_MIN are type-dependent and not provided by the supplied header files. MJD_MIN is a compile-time constant but MJD_MAX & TIMET_POSIX_MAX are run-time constants; the leap second table is ini- tialised by mirtime_getleaps(), timet2posix(...), or (on MirBSD) tzset(). mjd2timet() accepts certain cases where mjd->mjd is either (MJD_MAX + 1) or (MJD_MIN - 1), but not with all possible mjd->sec values. To obtain permitted ranges use timet2mjd(mjd, TIME_MAX) (or TIME_MIN) if necessary.
Some error conditions may raise an implementation-defined signal caused by signed integer truncation instead of returning an error indicator. mirtime_getleaps() does not report to the application; if the table is empty, either the system does not use leap seconds or an error occurred. It always succeeds, as does mirtime_isleap() as well as timet2mjd(). If the result is not representable in the output, mjd_explode() and thus timet2tm() truncate tm_year to INT_MAX (or INT_MIN) and return NULL; out- of-range data has mirtime_daylength() return 0 and posix2timet() return a value lower than the input (actually 0); timet2posix() always succeeds at this time but the introduction of negative leap seconds may change this. If the input was out of bounds or the result is not representable, XXX mjd_implode() raises an implementation-defined signal (caused by signed time_t integer truncation) or returns NULL; mjd2timet(), and tm2timet() thus, raise that signal or return (time_t)-1 setting errno to EOVERFLOW.
chroot(2), mktime(3), tzset(3)
This set of functions expects your operating system to not conform to IEEE Std 1003.1 ("POSIX.1") for correct time_t handling.
This API replaced a DJB-inspired TAI API with MirBSD #11.
mirabilos <m@mirbsd.org>
This API requires an int with at least 18 bit precision. Internal to the implementation long long must be wider than int. XXX tbd, also, int must fit into time_t now. XXX If int is wider than time_t, putting values not fitting into time_t in int fields or int function parameters will invoke Undefined Behaviour. Most arithmetic is unchecked if time_t is a floating point type. mjd_implode() requires the combination of tm_hour, tm_min, tm_sec and tm_gmtoff to fit in an int; given the types above, it is safe if time_t is >= 8 bit wider than int; else call mjd_explode(.day=TIME_MAX) and mjd_explode(.day=TIME_MIN) to obtain permissible value ranges. tm2timet() chains mjd_implode() to mjd2timet(). Before 2022, error handling was lacking or outright missing.
The leap second table is read from the timezone information file. This has implications on the location of the file and its up-to-dateness. There is no method to select POSIX-conformant behaviour (other than contrib/code/Snippets/posixtz.c). It's probably better this way, though. This code will cause compiler warnings on platforms with unsigned time_t but probably run; I'm not so sure if the same is true for platforms where it is a floating point type... same if type widths are unusual... MirBSD #10-current May 27, 2022 2