Comments from David R Tribble on ISO C 9X time proposal

Markus Kuhn Markus.Kuhn at
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>
From: David R Tribble <david.tribble at>
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 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
 time type.

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 [ 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
xtime type:

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
C9X draft.

--------------------.     +1-972-738-6125 Work  ,-.   C++: the PL/1 of
David R. Tribble     \   ,---------------------'   \  the 90s `-' +1-972-738-6111 Fax       `-------------------
dtribble at       
Support the anti-Spam amendment, join at

------- End of Forwarded Message

More information about the tz mailing list