Proposal for ISO C and C++ Extended-Range Time Type |
Author: | David R. Tribble, <david@tribble.com> |
Version: | 2.10, 1999-09-26 |
The standard header <time.h> shall contain declarations for the following types:
etime_t struct etime_tm
The etime_t type is a signed integer type at least 60 bits wide. It is capable of representing date and time values to the nearest microsecond across a range of about 20,000 years. The type represents the number of microsecond ticks since the zero date of the extended time epoch. Negative values represent dates prior to the zero date1. Whether or not leap seconds are represented is implementation defined2. (Note that leap seconds were not introduced until 1972, so that even if an implementation does represent leap seconds, it does so only for dates after that time.)
For purposes of conversions to and from other time encoding types (such as struct tm), the time encoded in type etime_t uses the proleptic Gregorian calendar3,4. Other representations and conversions adhere to the ISO-8601 standard for representing dates and times5.
Arithmetic operations can be performed on etime_t values, since it is a signed integer type. The difference between two etime_t values represents the difference in time between the two dates, i.e., the number of microseconds between them.
Relational operations can also be performed, providing an ordered relation between time values. The ETIME_UNKNOWN constant is guaranteed to compare less than any other time value, and the ETIME_NEVER constant is guaranteed to compare greater than any other time value (see the Constants section below).
The etime_tm structure type shall contain at least the following members, in an order such that they are part of a common initial subsequence of the tm structure (which is declared in the <time.h> header). The semantics of the members and their normal ranges are indicated in the comments.
int tm_sec; // Seconds after the minute, [0, 60] int tm_min; // Minutes after the hour, [0, 59] int tm_hour; // Hours since midnight, [0, 23] int tm_mday; // Day of the month, [1, 31] int tm_mon; // Months since January, [0, 11] int tm_year; // Year number (1 = AD0001), [-9,998, +9,999] int tm_wday; // Days since Sunday, [0, 6] int tm_yday; // Days since January 1st, [0, 365] int tm_isdst; // Minutes offset of DST, [-1, 60]
The tm_sec member has a range which allows for an additional leap second.
The tm_isdst member indicates the positive number of minutes of offset if Daylight Savings Time (DST) is in effect, zero if DST is not in effect, and -1 if the information is not available.
Note that the tm_year member has different semantics than the member of the tm and tmx structures. Instead of the number of years since 1900, it represents the calendar year number itself, and holds values in the range [-9,998, +9,999].
In addition, the structure contains the following members:
int tm_version; // Version number, 2 long int tm_zone; // Time zone offset from UTC in seconds, // [-86,400, +86,400] int tm_leapsecs; // Number of leap seconds applied
The tm_version member shall have a value of 2. The implementation or a future implementation of this structure may contain additional members. If so, the additional members shall follow the last member of the structure defined here (i.e., the tm_usec member), and the tm_version member shall have a value greater than 2.
The tm_zone member indicates the number of seconds offset of the local time zone from Coordinated Universal Time (UTC). A positive value indicates a time that is ahead of UTC.
Note that the tm_zone member differs from the member of the tm and tmx structures, in that it encodes the number of seconds of timezone offset rather than minutes.
The tm_leapsecs member indicates the number of leap seconds applied to the time value. This member shall have a value of -1 for implementations that do not account for leap seconds2.
In addition, the structure contains the following members:
int tm_len; // Length of the structure long int tm_usec; // Microseconds after the second, [0, 999,999]
The tm_len member specifies the size of the entire etime_tm structure.
The zero date of the extended time epoch is:
AD1601-01-01 00:00:00.000000 ZPositive etime_t values represent the number of microseconds after this date, and negative values represent the number of microseconds before this date.
While it is possible that the etime_t type can represent dates across a large span of years, only dates with four-digit years are considered valid. (For example, implementing the etime_t type as a a 64-bit signed integer type provides a representation that is capable of encoding dates from the year 16,666 B.C. to the year 19,867 A.D., but only a subset of this range contains valid dates.) Thus, the etime_t type is limited to representing dates within the range:
BC9999-01-01 00:00:00.000000 Z to AD9999-12-31 23:59:59.999999 ZIn other words, year numbers are limited to the range [-9,998, +9,999]. Values outside of this range do not represent valid dates. (See the descriptions of the ETIME_MIN and ETIME_MAX constants in the Constants section below.)
Date Value Notes n/a LLONG_MIN ETIME_UNKNOWN** -9998-01-01 00:00:00.000000 -366,029,020,800,000,000 ETIME_MIN -4712-01-01 12:00:00.000000 -199,218,916,800,000,000 Julian Day 0.0 -0000-01-01 00:00:00.000000 -50,522,659,200,000,000 1 B.C. 0001-01-01 00:00:00.000000 -50,491,123,200,000,000 1 A.D. 1600-12-31 00:00:00.000000 -86,400,000,000 One day before ZD* 1600-12-31 23:59:59.999999 -1 1 µsec before ZD* 1601-01-01 00:00:00.000000 +0 Zero date of epoch 1601-01-01 00:00:00.000001 +1 1 µsec after ZD* 1601-01-02 00:00:00.000000 +86,400,000,000 One day after ZD* 1602-01-01 00:00:00.000000 +31,536,000,000,000 One year after ZD* 1858-11-17 12:00:00.000000 +8,137,800,000,000,000 Julian day 2,400,000.5, MJD 0 1900-01-01 00:00:00.000000 +9,435,484,800,000,000 1900 A.D. 1970-01-01 00:00:00.000000 +11,644,473,600,000,000 POSIX epoch start 2000-01-01 00:00:00.000000 +12,591,158,400,000,000 2000 A.D. 2038-01-19 03:14:07.000000 +13,791,957,247,000,000 POSIX epoch end 2100-01-01 00:00:00.000000 +15,746,918,400,000,000 2100 A.D. +9999-12-31 23:59:59.999999 +265,046,774,399,999,999 ETIME_MAX n/a LLONG_MAX ETIME_NEVER**
These values do not account for leap seconds.
*
"ZD" means "zero date".
**
This assumes that the etime_t type is implemented using the
signed long long int type.
Extended time values may be converted to and from normalized encodings. The normalized encoding of an extended time value is a fixed-length array of unsigned character data, representing a series of bits. Such an encoding is a portable data format.
A normalized encoding for a given time value is equivalent to the value obtained by interpreting the bytes comprising the unsigned character array as if they are a signed binary integer that is ETIME_NORMLEN bytes in length. Thus the equivalence between the normalized extended time value contained in array n and its corresponding etime_t value t is:
t = ((((... n[0] * (UCHAR_MAX+1) + n[1]) * (UCHAR_MAX+1) + n[2]) * (UCHAR_MAX+1) + n[3]) * (UCHAR_MAX+1) + ...) + n[ETIME_NORMLEN-1];
The normalized encoding of a time value does not take into account leap seconds2, regardless of whether or not the implementation properly accounts for leap seconds in the representation of the etime_t type.
The standard header <time.h> shall contain declarations for the following library constants:
ETIME_MAX ETIME_MIN ETIME_NEVER ETIME_NORMLEN ETIME_UNKNOWN
const etime_t ETIME_MAX;
The ETIME_MAX constant represents the highest (i.e., latest) valid time value, which is the encoding of the date:
AD9999-12-31 23:59:59.999999 ZIt is equal to at least the value +265,046,774,399,999,999. If the implementation accounts for leap seconds, the value will be larger and will encode the date:
AD9999-12-31 23:59:60.999999 Z
const etime_t ETIME_MIN;
The ETIME_MIN constant represents the lowest (i.e., earliest) valid time value, which is the encoding of the date:
BC9999-01-01 00:00:00.000000 ZIt is equal to the value -366,029,020,800,000,000. (Note that leap seconds do not occur in dates prior to 1972.)
const etime_t ETIME_NEVER;
The ETIME_NEVER constant represents a time that will never occur, i.e., a time in the future that will never be reached. It is equal to the maximum possible etime_t value. (For example, if the etime_t type is implemented using the signed long long int type, then the maximum value is LLONG_MAX.) This value is guaranteed to compare greater than any other etime_t value.
#define ETIME_NORMLEN integer-expression
The ETIME_NORMLEN constant is a macro that evaluates to an integer expression specifying the size of a normalized extended time value.
(60 + CHAR_BIT - 1) / CHAR_BIT(For example, this value is 8 for implementations having 8-bit characters.)
const etime_t ETIME_UNKNOWN;
The ETIME_UNKNOWN constant represents an unknown time. It is equal to the minimum etime_t value possible. (For example, if the etime_t type is implemented using the signed long long int type, then the minimum value is LLONG_MIN.) This value is guaranteed to compare less than any other etime_t value.
The standard header <time.h> shall contain declarations for the following library functions:
etime() etime_add() etime_denorm() etime_diff() etime_fromtime() etime_fromtm() etime_fromtmx() etime_gmtime() etime_localtime() etime_mktime() etime_norm() etime_sub() etime_totime() etime_totm() etime_totmx()
bool etime(etime_t *tp);
The etime() function sets the value pointed to by tp to the current system time. The value is guaranteed to be accurate to at least the nearest second. The value represents the time to the nearest microsecond, but is accurate only to the precision that the system is capable of representing time. (For example, if the implementation is capable of discerning time only to the nearest millisecond, the resulting extended time value will only be accurate to the nearest millisecond.) The value is guaranteed to be within the range [ETIME_MIN, ETIME_MAX] or be the value ETIME_UNKNOWN.
If successful, the function returns true. If the system time is not available, the value pointed to by tp is set to ETIME_UNKNOWN and the function returns false. If tp is a null pointer, no assignment is attempted and the function returns true or false as stated previously6.
bool etime_add(const struct etime_tm *a, const struct etime_tm *d, struct etime_tm *b);
The etime_add() function adds the broken-down time in the structure pointed to by d to the broken-down time in the structure pointed to by a, storing the result in the structure pointed to by b. The structure pointed to by d represents the delta time between the time at a and the resulting time at b. In other words, it specifies the number of years (tm_year), then months (tm_mon), then days (tm_mday), then hours (tm_hour), then minutes (tm_min), then seconds (tm_sec), and then microseconds (tm_usec) that are to be added to the time at a to make it equal to the time at b. All other members of the structure pointed to by d are ignored. The resulting time at b represents a time after (i.e., later than) the time at a. Undefined behavior results if any of the members of the structure at d mentioned above are not positive.
If, after the delta time has been added to time at a, the resulting date is invalid (i.e., represents a time later than ETIME_MAX), the members of the structure pointed to by b are set to values that represent the time ETIME_MAX. Otherwise, the resulting member values are guaranteed to represent a time within the range [ETIME_MIN, ETIME_MAX].
If the time at a does not represent a valid time (i.e., if one or more of the structure members have improper values), the results are undefined.
If successful, the function returns true. If an error occurs, the object pointed to by b is not changed and the function returns false. If pointer a or pointer d is a null pointer, none of the members of the structure at b are modified and the function returns false. If pointer b is a null pointer, no assignment is attempted and the function returns false.
bool etime_denorm(const unsigned char n[ETIME_NORMLEN], etime_t *tp);
The etime_denorm() function decodes the normalized, portable character data in n into an extended time value, storing the resulting value in the object pointed to by tp. The resulting extended time value is guaranteed to be within the range [ETIME_MIN, ETIME_MAX], or the value ETIME_UNKNOWN or ETIME_NEVER.
If successful, the function returns true. If the encoded value in n does not represent a valid date or either of the values ETIME_UNKNOWN or ETIME_NEVER, The object pointed to by tp is set to ETIME_UNKNOWN and the function returns false. If either pointer n or tp is a null pointer, no assignment is attempted and the function returns false.
bool etime_diff(const struct etime_tm *a, const struct etime_tm *b, struct etime_tm *d);
The etime_diff() function determines the delta time between the broken-down times pointed to by a and b, placing the results in broken-down form into the structure pointed to by d. The delta time represents the absolute difference between time a and time b. In other words, it specifies the number of years (tm_year), then months (tm_mon), then days (tm_mday), then hours (tm_hour), then minutes (tm_min), then seconds (tm_sec), and then microseconds (tm_usec) that must be added to the the time at a to make it equal to the time at b. All other members of the structure pointed to by d are set to zero.
If successful, the members of the structure at d are set to positive values, and the function returns true. If the structure at a represents a time that is later than the time in the structure at b, the results are undefined. If an error occurs, the object pointed to by d is not changed and the function returns false. If d is a null pointer, no assignment is attempted and the function returns false.
bool etime_fromtime(const time_t *xp, etime_t *tp);
The etime_fromtime() function converts the time_t value pointed to by xp into its equivalent etime_t time, storing the result in the object pointed to by tp.
If successful, the resulting value is guaranteed to be within the range [ETIME_MIN, ETIME_MAX], and the function returns true. If unsuccessful or if an error occurs, the function returns false. If either xp or tp is a null pointer, no conversion occurs and the function returns false.
bool etime_fromtm(const struct tm *xp, struct etime_tm *sp);
The etime_fromtm() function converts the broken-down time structure pointed to by xp into its corresponding broken-down time structure pointed to by sp. The members of the resulting structure object at sp shall have normalized values (in particular, the tm_year member will have a value in the range [-9,998, +9,999]), provided that the date represented by the object at xp is valid (i.e., within the range [ETIME_MIN, ETIME_MAX]), otherwise the members of the structure at sp are set to zero.
If successful, the function returns true. If unsuccessful or if an error occurs, the function returns false. If either pointer xp or sp is a null pointer, no conversion occurs and the function returns false.
bool etime_fromtmx(const struct tmx *xp, struct etime_tm *sp);
The etime_fromtmx() function converts the broken-down time structure pointed to by xp into its corresponding broken-down time structure pointed to by sp. The members of the resulting structure object at sp shall have normalized values (in particular, the tm_year member will have a value in the range [-9,998, +9,999]), provided that the date represented by the object at xp is valid (i.e., within the range [ETIME_MIN, ETIME_MAX]), otherwise the members of the structure at sp are set to zero.
If successful, the function returns true. If unsuccessful or if an error occurs, the function returns false. If either pointer xp or sp is a null pointer, no conversion occurs and the function returns false.
bool etime_gmtime(etime_t t, struct etime_tm *sp);
The etime_gmtime() function converts the time value t into its corresponding broken-down time value pointed to by sp, relative to UTC time. The members of the etime_tm structure object pointed to by sp are set to normalized values. The tm_year member of the structure is set to a value in the range [-9,998, +9,999].
If successful, the function returns true. If an error occurs, the object pointed to by sp is not changed and the function returns false. If time t is ETIME_UNKNOWN or ETIME_NEVER, all of the members of the structure at sp are set to zero and the function returns false. If sp is a null pointer, no assignment is attempted and the function returns false.
bool etime_localtime(etime_t t, struct etime_tm *sp);
The etime_localtime() function converts the time value t into its corresponding broken-down time value pointed to by sp, taking into account the local timezone offset from UTC. The members of the etime_tm structure object pointed to by sp are set to normalized values. The tm_year member of the structure is set to a value in the range [-9,998, +9,999].
If successful, the function returns true. If an error occurs, the value pointed to by s is not changed and the function returns false. If time t is ETIME_UNKNOWN or ETIME_NEVER, all of the members in the structure at sp are set to zero and the function returns false. If sp is a null pointer, no assignment is attempted and the function returns false.
bool etime_mktime(const struct etime_tm *sp, etime_t *tp);
The etime_mktime() function converts the broken-down time value pointed to by sp into its equivalent etime_t value, storing the result into the object pointed to by tp. The resulting value at tp is guaranteed to be within the range [ETIME_MIN, ETIME_MAX], provided that the date represented by the structure object at sp is valid, otherwise t is set to ETIME_UNKNOWN.
If successful, the function returns true. If unsuccessful or if an error occurs, the function returns false. If either sp or tp is a null pointer, no conversion occurs and the function returns false.
bool etime_norm(etime_t t, unsigned char n[ETIME_NORMLEN]);
The etime_norm() function encodes the extended time value t into normalized, portable character data, storing the resulting data in array n.
The resulting encoded time does not take into account leap seconds, regardless of whether or not the implementation's representation of the etime_t type does so2.
If successful, the function returns true. If value t is not within the range [ETIME_MIN, ETIME_MAX] and is not the value ETIME_UNKNOWN or ETIME_NEVER, the resulting data in n is set to an encoding for the value ETIME_UNKNOWN and the function returns false. If n is a null pointer, no assignment is attempted and the function returns false.
bool etime_sub(const struct etime_tm *a, const struct etime_tm *d, struct etime_tm *b);
The etime_sub() function subtracts the broken-down time in the structure pointed to by d from the broken-down time in the structure pointed to by a, storing the result in the structure pointed to by b. The structure pointed to by d represents the delta time between the time at a and the resulting time at b. In other words, it specifies the number of years (tm_year), then months (tm_mon), then days (tm_mday), then hours (tm_hour), then minutes (tm_min), then seconds (tm_sec), and then microseconds (tm_usec) that are to be subtracted from the time at a to make it equal to the time at b. All other members of the structure pointed to by d are ignored. The resulting time at b represents a time before (i.e., earlier than) the time at a. Undefined behavior results if any of the members of the structure at d mentioned above are not positive.
If, after the delta time has been subtracted from the time at a, the resulting date is invalid (i.e., represents a time earlier than ETIME_MIN), the members of the structure pointed to by b are set to values that represent the time ETIME_MIN. Otherwise, the resulting member values are guaranteed to represent a time within the range [ETIME_MIN, ETIME_MAX].
If the time at a does not represent a valid time (i.e., if one or more of the structure members have improper values), the results are undefined.
If successful, the function returns true. If an error occurs, the object pointed to by b is not changed and the function returns false. If pointer a or pointer d is a null pointer, none of the members of the structure at b are modified and the function returns false. If pointer b is a null pointer, no assignment is attempted and the function returns false.
bool etime_totime(etime_t t, time_t *xp);
The etime_totime() function converts the etime_t value t into its equivalent time_t time, storing the result in the object pointed to by xp.
If successful, the function returns true. If unsuccessful or if an error occurs, the function returns false. If the time represented by the value t is ETIME_UNKNOWN or ETIME_NEVER, or if it cannot be represented by a time_t value, the value pointed to by xp is set to the minimum or maximum meaningful time_t value, as appropriate, and the function returns false. If xp is a null pointer, no conversion occurs and the function returns false.
bool etime_totm(const struct etime_tm *sp, struct tm *xp);
The etime_totm() function converts the broken-down time structure pointed to by sp into its corresponding broken-down time structure, storing the results in the object pointed to by xp. The members of the resulting structure at xp shall have normalized values (in particular, the tm_year member shall have a value in the range [-11,898, +8,099]), provided that the date represented by the object at sp is valid (i.e., within the range [ETIME_MIN, ETIME_MAX]), otherwise the members of the structure at xp are set to zero.
If successful, the function returns true. If unsuccessful or if an error occurs, the function returns false. If either sp or xp is a null pointer, no conversion occurs and the function returns false.
bool etime_totmx(const struct etime_tm *sp, struct tmx *xp);
The etime_totmx() function converts the broken-down time structure pointed to by sp into its corresponding broken-down time structure, storing the results in the object pointed to by xp. The members of the resulting structure at xp shall have normalized values (in particular, the tm_year member shall have a value in the range [-11,898, +8,099]), provided that the date represented by the object at sp is valid (i.e., within the range [ETIME_MIN, ETIME_MAX]), otherwise the members of the structure at xp are set to zero.
It is implementation-defined whether or not the tm_ext member of the structure at xp is null. If it is not null, then the object to which it points shall be allocated as if by a call to malloc() (which is declared in the <stdlib.h> header).
If successful, the function returns true. If unsuccessful or if an error occurs, the function returns false. If either sp or xp is a null pointer, no conversion occurs and the function returns false.
BC4713-01-01 12:00:00 Z Julian day 0.0 (LY) BC0001-01-01 00:00:00 Z 1 B.C. (LY) AD0001-01-01 00:00:00 Z 1 A.D. AD1600-01-01 00:00:00 Z (LY) AD1601-01-01 00:00:00 Z COBOL-90 and Win32 epoch start AD1858-11-17 12:00:00 Z MJD 0.0, VMS epoch start AD1900-01-01 00:00:00 Z ISO struct tm min year, IBM ESA epoch start AD1970-01-01 00:00:00 Z POSIX epoch start AD2000-01-01 00:00:00 Z (LY) AD2001-01-01 00:00:00 Z 2001 A.D., a MondayDates marked with (LY) are leap years.
I wish to thank Jay Crisman for his comments on an early draft, which led to the idea of constrainting year numbers to four-digit numbers.
I wish to thank Darron Shaffer for his comments, and for the idea of the normalized portable character encoding functions.
Email comments to David Tribble at
<david@tribble.com>.
David Tribble's home page is at
<http://david.tribble.com/>.
Copyright ©1998-1999, by David R. Tribble, all rights reserved.
All trademarks are the property of their respective owners.
THIS DOCUMENT IS OBSOLETE AND HAS BEEN SUPERSEDED BY: http://david.tribble.com/text/c0xlongtime.html.