Comments from David R Tribble on ISO C 9X time proposal
Markus.Kuhn at cl.cam.ac.uk
Fri Oct 2 13:41:38 UTC 1998
Here are a number of good comments on the modernized <time.h> from an
author of a related proposal, which I'd like to share with those of you
interested in this project.
------- Forwarded Message
Date: Tue, 22 Sep 1998 15:11:31 -0500
To: Markus Kuhn <markus.kuhn at cl.cam.ac.uk>
From: David R Tribble <david.tribble at dallas.beasys.com>
Subject: new time.h comments
I have some comments on your new <time.h> proposal. Some of these ideas
came from my original proposal concerning an extended-precision time type
(which I have abandoned for the time being; the text is still available at
http://www.flash.net/~dtribble/text/c0xtime.htm if you're interested).
1. I would prefer that the macro names begin with an '_' in order to keep
them out of the user's identifier name space. Thus, you would have names
like '_TIME_UTC', '_TIME_TAI', etc.
2. It would be nice to have the concept of an 'unknown' or 'unspecified'
time. Such a value would indicate a time value that is not (yet) known
or a time value that has not (yet) been set to a valid time. This could
be defined as a special constant named '_TIME_UNKNOWN'. Arithmetically,
this value would compare less than all other valid time values.
3. Similarly, it would be nice to have the concept of a 'never' time, i.e.,
a time that has not yet occurred or a point in time that will never be
reached. This could also be considered as something akin to a 'maximum'
time value. This could be defined as a special constant named '_TIME_NEVER'.
Arithmetically, this value would compare greater than all other valid time
4. You have defined the ability to determine the resolution of the time
type, but there is no way to determine the valid range that time values
span. This could be done by defining the macros '_TIME_MIN_YEAR' and
'_TIME_MAX_YEAR' which specify, respectively, the earliest year containing
Jan 1 and the latest year containing Dec 31, that are representable by the
5. Of the 'TIME_XXX' macros defined, only the last three (TIME_LOCAL,
TIME_SYNC, and TIME_RESOLUTION) need to be disjoint bitmask values; the
remaining macro values can simply be distinct numeric values (such as 1,
2, 3, 4, etc.). (Personally, I don't like constants used for commands to
include a zero value; zero to me means "undefined" or "unknown".)
6. The TIME_UTC epoch is defined as starting at 1970-01-01, but has no
well-defined value until after 1972-01-01. Why not just define the epoch
as beginning at 1972-01-01?
7. By the same token, the TIME_TAI epoch is defined as starting as
1970-01-01 but has no well-defined values until after 1972-01-01. Why
not just start the epoch at 1972-01-01?
8. You need to be careful that, when describing the TIME_TAI epoch and
times reckoned within that epoch, that you do not imply that such reckoning
*requires* accuracy to external TAI time sources (i.e., make it clear that
synchronization with outside time counters is purely optional.) Some
people might misinterpret this as an implied requirement, and use it as
justification to ignore your proposal.
9. The flaw with the TIME_TAI representation is that, even though single
leap seconds are taken into account in the encoding, the difference between
two TAI times does not properly account for the true number of leap
seconds between them. Perhaps a function should exist for the sole purpose
of deriving the difference between two (TAI) times which does take into
account all intervening leap seconds, to wit:
int diffxtime(struct xtime *diff, const struct xtime *a,
const struct *xtime b);
Fills in '*diff' with the difference between 'a' and 'b'.
Returns i<0 if 'a' is before 'b', or i>0 if 'a' is after 'b', else 0.
Perhaps an 'int clock_type' argument is needed, too.
10. The TIME_MONOTONIC epoch is defined as beginning at the last system
reset. Some systems are not capable of discerning time this way, and can
only reckon time from the start of the current process. Indeed, the
standard clock() function is defined with this in mind. Perhaps the
TIME_MONOTONIC epoch should be defined similarly.
11. TIME_PROCESS and TIME_THREAD fill a definite need, a la the times()
call of POSIX. However, there is no way to ascertain the total elapsed
CPU time for *child* processes. Perhaps a TIME_PROCESS_CHILDREN?
12. There ought to be a way to retrieve information for the local timezone.
The definition of tz_prep() states that a null argument returns information
about "some externally defined default timezone". A better definition
would return information about "the local timezone, possibly determined
from some external source (such as the program execution environment)".
Alternatively, another function could be defined for the sole purpose of
retrieving the local timezone information, such as:
int tz_local(timezone_t *tz);
13. The calling convention to tz_prep() could be made better, to wit:
int tz_prep(timezone_t *tz, const char *restrict tzstring);
On success, the function shall set the contents of the object pointed to
by 'tz' with the appropriate timezone information. This is better because
tz_prep() does not then need to allocate any memory (it is allocated by
the caller instead). This means that tz_free() is not needed. AFAIK, no
standard library functions explicitly allocate memory, and the ISO
committee has tried in the past to avoid inventing functions that do so.
14. The xtime_breakup() function ignores xtp->nsec, which is a shame. As
I have suggested in other postings and in my proposal, it would be nice to
have access to subsecond precision in the 'tm' structure, but this poses
a problem with binary compatibility with existing code. What we are left
with, then, is the need to access both the broken-down 'tm' structure and
the original xtime value, so that we have access to the full time
information. (On a tangent note, I don't like the name; perhaps something
like xtime_split() or xtime_expand()?)
15. Similarly (as I have suggested previously), strftime() and strxftime()
should contain a format specifier for fractional seconds (subseconds).
Your proposal provides this ability. An alternative approach would be
to add conversion specifiers for getting at the subseconds, such as:
%q milliseconds (3 digits, not rounded)
%Q microseconds (6 digits, not rounded)
(If conversion size specifiers are added, we would only need one specifier
16. In spite of your desire to obsolete the time_t type, we will still need
a way of converting between xtime and time_t types, if for no other reason
than for providing a smoother transition away from time_t. Without explicit
conversion functions, the only alternative is to convert by first
converting to struct 'tm' values, which seems unnecessarily wasteful.
17. I agree that the 'tmx' structure, with its tm_ext member, is an
ill-conceived invention by the ISO committee. There ought to be a better
way to allow for future extentions without the need for an extra allocation
area. How this chunk is allocated, deallocated, and passed to other
functions is never discussed in the draft.
18. You are slightly incorrect about Microsoft using a float type for
time_t; they use a 32-bit signed binary integer identical to the POSIX
time_t type. Apple's Rhapsody O/S, however, uses a 'double' for times and
19. Minor typos:
1.2.1, xtime_get(), "Returns":
<If time != NULL then> should be <If xtp != NULL then>.
1.4.4, strfxtime(), "Description":
<full stop> should be <period>;
<decimal dot or decimal comma> should be <decimal-point period or
comma>, see wording in [18.104.22.168 localeconv()] for consistency.
2, Rationale, "Lack of control over timezone":
<proofed> should be <proved>.
2, Rationale, "POSIX and BSD predecessors":
<problematic> should be <problem>.
One final suggestion, pertaining to your choice of representation for the
You might want to consider implementing the xtime type as a 64-bit signed
binary integer value instead of a structure. Either 'long long int' or
'int_least64_t' would be appropriate, with the value of a given time t is:
t = (sec x 2 x 10^6) + usec + (Lsec x 10^6)
where 'sec' is the number of seconds since the start of the epoch,
'usec' is the number of microseconds since that second, and
'Lsec' is 1 if a leap second is present, otherwise it is 0.
This encoding seems to accomplish the same goals as your xtime structure,
with the advantage that, since it is a simple arithmetic type, computations
can be performed on it more efficiently. And it is smaller than the
structure (64 bits wide instead of 96). These make it more amenable for
directly storing it in binary data files and transmitting across networks.
Even though it has less high bits, it is still capable of representing
time to the nearest microsecond across a range of over 146,000 years
(BC73000 to AD73000), which should be quite sufficient for most applications.
The only real difference between this type and your xtime type is the
resolution; I think that microsecond precision would be useful for most
applications. (Of course, we could push the resolution up by a factor of
ten, encoding 100 nsec ticks instead of usecs, which would reduce the
range down to BC7300-AD7300, or BC4713-AD9900.)
I hope these comments help. I, too, am quite serious about getting a useful
and "correct" set of time/date functions into the new C9X standard. I am
in the process of feeding my suggestion to Clive Feather, who has expressed
an interest in collecting such comments and rewriting section 7.23 of the
--------------------. +1-972-738-6125 Work ,-. C++: the PL/1 of
David R. Tribble \ ,---------------------' \ the 90s
http://www.beasys.com `-' +1-972-738-6111 Fax `-------------------
dtribble at technologist.com http://www.flash.net/~dtribble
Support the anti-Spam amendment, join at http://www.cauce.org/
------- End of Forwarded Message
More information about the tz