First proposal for new ISO C 9x time API
Markus Kuhn
Markus.Kuhn at cl.cam.ac.uk
Fri Sep 4 19:28:47 UTC 1998
I think, I have come up with a nice C API that fulfills all the stated
requirements. At the moment, it is just a first design sketch, not
something that could already be pasted into ISO C, but please have a
look at it and think about whether you would like this <xtime.h> to
become the successor of the quite broken <time.h>. The API below have
fewer functions and yet provides much more functionality than <time.h>.
I think that the approach below is more practical that Dan Bernstein's
completely TAI-based API. My API does not require any leapsecond history
to be stored in the system, something which I would never expect to be
updated reliably in practice.
Markus
--
Markus G. Kuhn, Security Group, Computer Lab, Cambridge University, UK
email: mkuhn at acm.org, home page: <http://www.cl.cam.ac.uk/~mgk25/>
//
// <xtime.h>
//
// Proposal for a modern time and calendar API for ISO C 9x - first sketch
//
// Markus Kuhn <mkuhn at acm.org> -- 1998-09-04
//
// Note: The names of objects are not yet final and have likely to be
// changed for backwards compatibility reasons.
// The <xtime.h> API is added to the existing <time.h>. The old
// <time.h> is not modified, maintained for backwards compatibility,
// and declared deprecated. The old <time.h> can be implemented
// completely on top of the the <xtime.h> functions.
//
#include <stdint.h>
// arithmetic time (replacing both time_t and clock_t, on POSIX systems
// often bit compatible with struct timespec)
struct xtime {
int_fast64_t sec; // seconds since the epoch
int_fast32_t nsec; // nanoseconds [0, 1_999_999_999]
};
// query the clock(s)
#define TIMEOPT_UTC 1
#define TIMEOPT_TIA 2
#define TIMEOPT_LOCAL 4
#define TIMEOPT_SYNC 8
#define TIMEOPT_MONOTONIC 16
#define TIMEOPT_PROCESS 32
#define TIMEOPT_THREAD 64
void get_xtime(struct xtime *time, int *options);
/* Function get_xtime(&time, &options) queries the clock and writes one
* form of time into *time. The variable *options specifies which form of
* time is requested and contains after the call some status bits that
* indicate properties of the form of time that has been returned.
*
* The possible properties are:
*
* TIMEOPT_UTC the epoch is 1970-01-01 00:00:00 UTC and time->sec
* does not count inserted leap seconds and did count
* removed leap seconds as if they hadn't been removed.
* During a leap second (if the implementation is aware
* of it), time->sec shows the value for the previous
* second and time->nsec continues to increase in the
* range 1e9 .. 2e9-1.
*
* TIMEOPT_TAI the epoch is 1970-01-01 00:00:00 TAI and time->sec
* does count inserted leap seconds and does not count
* removed leap seconds. time->nsec < 1_000_000_000.
*
* TIMEOPT_LOCAL the epoch is 1970-01-01 00:00:00 in the local time
* zone. This is only a fallback option for systems
* that are ignorant of UTC and know nothing but some
* local time. TIMEOPT_LOCAL need not be supported on
* systems that support TIMEOPT_UTC.
*
* TIMEOPT_SYNC Can appear only together with TIMEOPT_UTC and
* TIMEOPT_TAI and indicates that the system has so
* frequently been synchronized with an official time
* source such that with high probability the deviation
* from UTC resp. TAI is less than 1 s.
*
* TIMEOPT_MONOTONIC The time comes from a clock with the following
* property: If A and B are readings taken from this
* clock (in seconds since the epoch) and TA and TB are
* the corresponding TIMEOPT_TAI readings, then
* 1-1/2000 < (A-B)/(TA-TB) < 1+1/2000. In other words,
* the frequency of a monotonic clock is never off
* more than 500 ppm, a target that cheap clock oscillators
* in office equipment can easily guarantee. This clock
* cannot be reset while the process is running and
* it will never show a leap second: time->nsec <
* 1_000_000_000. TIMEOPT_MONOTONIC is guaranteed to be
* always available.
*
* TIMEOPT_PROCESS The epoch is the start of this process and the
* measured time is the CPU time consumed by this process
* so far. TIMEOPT_PROCESS is guaranteed to be always
* available.
*
* TIMEOPT_THREAD The epoch is the start of this thread and the
* measured time is the CPU time consumed by this thread
* so far. TIMEOPT_PROCESS is guaranteed to be always
* available. On systems without multithreading,
* we always have TIMEOPT_THREAD == TIMEOPT_PROCESS.
*
* The status bits TIMEOPT_UTC, TIMEOPT_TAI, and TIMEOPT_LOCAL
* are mutually exclusive. TIMEOPT_SYNC can only appear together with
* TIMEOPT_UTC and TIMEOPT_TAI.
*
* The variable *options is used by the caller to select what type of
* clock is requested, by specifying one of TIMEOPT_UTC, TIMEOPT_TAI,
* TIMEOPT_MONOTONIC, TIMEOPT_PROCESS, or TIMEOPT_THREAD in the value
* provided to get_time(). The caller then has to check in the returned
* options variable, whether the bit is still set to find out whether
* the required time was known.
*
* The TIMEOPT_MONOTONIC value can at boot time be equivalent with any
* of the other clocks, but it can also have its epoch at boottime.
* TIMEOPT_MONOTONIC, TIMEOPT_PROCESS, and TIMEOPT_THREAD are the only
* clocks guaranteed to be available on all implementations.
*
* If a TIMEOPT_MONOTONIC value is given to mkxtm, the resulting
* broken-down time might not be very meaningful. If TIMEOPT_LOCAL
* is given to mkxtm, then zonespec should be TZ_UNDEFINED such that
* the xtm value reflects that the precise epoch is not known.
*
* Implementation example:
*
* A typical desktop system will have only TIMEOPT_UTC,
* TIMEOPT_MONOTONIC, TIMEOPT_PROCESS, and TIMEOPT_THREAD available.
* After boot, we will have TIMEOPT_UTC == TIMEOPT_MONOTONIC until
* someone adjusts the system clock. TIMEOPT_MONOTONIC will not be
* affected by this adjustment, TIMEOPT_UTC will be a best effort
* estimate of UTC. If the system has a leap seconds file that is less
* than 6 months old or is connected to a GPS receiver, then
* TIMEOPT_TAI might also be available. Note that systems have no need
* to store the leap second history, because no function of this API
* allows to convert between UTC and TAI.
*
* TIMEOPT_LOCAL need not be available on systems that have
* TIMEOPT_UTC. Local time should preferably be determined by
* specifying TZ_DEFAULT or the respective local time zone to
* mkxtm.
*
* Systems without a battery clock will not have TIMEOPT_UTC available
* after boot time, but TIMEOPT_MONOTONIC can already be used to make
* time measurements and can also be used to backdate timestamps that
* were made before UTC became known (e.g., by a network communication
* or a radio clock lock-on).
*
*/
// internal efficient representation of a time zone rule
typedef struct { ... } timezone_t;
// generate a timezone_t description from a string (e.g., POSIX.1 TZ format
// or Olsen database entry, or ...). Return *zone = NULL if there is
// some syntax error in the string.
void prepare_timezone(timezone_t **zone, char *zonespec);
// free the time zone descriptor zone and set *zone == TZ_UTC to remove
// dangling pointers
void free_timezone(timezone_t **zone);
// some predefined time zone descriptors
#define TZ_UTC (timezone_t *) 0
#define TZ_UNDEFINED (timezone_t *) -1
#define TZ_DEFAULT (timezone_t *) -2 // eg. from environment var TZ, etc.
/* When we use mkxtm() to split a xtime value up into a calendar date
* and a hhmmss time (struct xtm), then we have to specify in which
* time zone this time should be. If we are happy with UTC, we specify
* TZ_UTC, and we will get offset==0. If the xtime value is not an
* approximation of a UTC timestamp, then we specify TZ_UNDEFINED,
* which indicates in struct tmx that offset is meaningless. If we
* want to have whatever the system sees as its default or local time
* zone, then we specify TZ_DEFAULT. We can select any other time zone
* by parsing a time zone description with timezone() and specifying
* the result. */
// brocken down date and time
struct xtm {
long nsec; // nanoseconds after the second [0, 999_999_999]
int sec; // seconds after the minute [0, 60]
int min; // minutes after the hour [0, 59]
int hour; // hours since midnight [0, 23]
int mday; // day of the month [1, 31]
int mon; // months since December [Jan=1, Dec=12]
int year; // number of the year
int wday; // days since Sunday [Mon=1, Sun=7]
int week; // calendar week number (ISO 8601) [1, 53]
int wyear; // year of the current week (ISO 8601)
int yday; // days since December 31 [1, 366]
int offset; // minutes east off UTC
int repeat; // flag indicating first hour after DST
timezone_t *zone; // time zone descriptor
};
/*
* Note that in xtm, leap seconds are indicated by sec==60 and not by
* and nsec overflow.
*/
// display a brocken down time
size_t strfxtime(char * restrict s,
size_t maxsize,
const char * restrict format,
const struct xtm * restrict timeptr);
// construct a xtime value from a broken down date and time (return -1
// on error, 0 else)
int mkxtime(const struct xtm *src, struct xtime *dest);
// construct a brocken down date/time representation from an xtm value
// (return -1 on error, 0 else)
int mkxtm(const struct xtime *src, const timezone_t *zone, struct xtm *dest);
/*
* In time zones with summer time switches, the first hour of winter time
* repeats the time values of the previous hour. To distinguish these values
* the flag repeat is set to one. (May be, we can also keep the old DST
* flag here instead)
*
* In the tmx given to mkxtime, only the components nsec, sec, min,
* hour, mday, mon, year, offset, repeat, and zone are examined. The
* values of the other components are irrelevant. Values that are out
* of range in nsec, sec, min, hour, mday, mon, year are adjusted
* accordingly, for instance if sec is negative, then 60 is added to
* sec while 1 is subtracted from min until the value is in the
* correct interval before conversion takes place. If zone ==
* TZ_UNDEFINED, then mkxtime behaves exactly as if TZ_UTC.
*/
More information about the tz
mailing list