First proposal for new ISO C 9x time API

Joseph S. Myers jsm28 at
Fri Sep 4 20:38:38 UTC 1998

On Fri, 4 Sep 1998, Markus Kuhn wrote:

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

This seems like a reasonably clean solution - some comments are below.

> //       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.

I would say there should be functions to convert between time_t and struct
xtime (either way) (possibly with information loss, which should be

>  * 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.

> // 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);

(Of course, that should be const char *zonespec, with maybe some

NULL could also occur on other errors - I would suggest having a function
to give an error string (so that e.g. problems with timezone files can
readily be diagnosed) which would probably entail a change in the
interface so that information about the particular error could be saved
(remember re-entrancy).

For this to be useful it will probably be necessary to copy the POSIX.1
TZ specification into C9X - but it shouldn't be needed to specify what
environment variables are used.

> // free the time zone descriptor zone and set *zone == TZ_UTC to remove
> // dangling pointers

I would say setting to TZ_UTC is a quality-of-implementation issue and the
standard should simply make *zone undefined after it is freed.

In addition state that copies of the timezone_t cannot be used after it is
freed.  (This assumes copying timezone_t is allowed; if it is, do we
require it to be a structure type or simply an object type other than an
array type?).

> void free_timezone(timezone_t **zone);

> #define TZ_DEFAULT   (timezone_t *) -2   // eg. from environment var TZ, etc.

There should be two distinct concepts: user's timezone, possibly depending
on the environment, and the system's best idea of the local timezone that
is guaranteed not to depend on the environment.

> struct xtm {

It would be a good idea to use a common prefix for the structure elements
(xtm_nsec, xtm_sec, etc.).

>   long  nsec;   // nanoseconds after the second [0, 999_999_999]
>   int   sec;    // seconds after the minute [0, 60]

Where the nanoseconds value in a struct xtime is >= 10^9, the conversion
should be defined as long as the seconds point to the end of a minute in
the timezone used for conversion.  However, POSIX.1 timezones allow
offsets that are not whole minutes: in such cases it is probably best to
make the conversion in the vicinity of a leapsecond implementation defined
(but still require the nsec value in the result to be <10^9?).

>   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

Seconds might be better.

>   int   repeat; // flag indicating first hour after DST

Repetitions can also occur when standard time changes - perhaps this
should indicate which (0, 1, 2, ...) of the successive occurances of that
time as local time in the given timezone is meant?  However, if we are
concerned about this, an interface would be needed to tell whether a given
time is ambiguous and find all the times it could mean.

>   timezone_t *zone;  // time zone descriptor
> };

> // 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.
>  */

What is appropriate in canonicalisation if the seconds value is 60?  The
natural expectation is that this causes the minutes to increase unless we
are at a leapsecond - but this requires a leapseconds table.  The
alternative, ending up with nanoseconds of 10^9 in the struct xtime, seems

Missing from the specification is some way to tell the precision of the
system clock (i.e. some analogue of clock_getres from POSIX).

Also, some analogue of difftime to find the difference between two (UTC)
times, which should fail if up-to-date leapsecond information is not
available for the relevant period.  It's not clear if this should be part
of the standard, but Clive Feather's issues include conversion between UTC
and TAI so I suppose some applications need a leapsecond table to be

Joseph S. Myers
jsm28 at

More information about the tz mailing list