You convinced me inetutils (and many other programs) has real bugs
related to ctime today that should be fixed.  Now I want to figure out
what the best fix to existing code is.

Paul Eggert <egg...@cs.ucla.edu> writes:

>> Another idea is to have gnulib's ctime augment the C standard to have
>> ctime not be undefined but to return shorter and longer strings, which I
>> believe is still consistent with the C standard?
>
> I would look askance at any Gnulib implementation of ctime that does
> this sort of thing. The ctime API is so poorly designed that callers 
> should use some other API. This is partly why C23 is deprecating
> ctime. Gnulib shouldn't encourage ctime's continued use.

If gnulib provides a simple to use replacement with clear documented
semantics and interface, and a clear upgrade path from current ctime, it
seems okay to give up on trying to use the ctime API.

Perhaps more than one upgrade path is needed, to accomodate different
situations: the inetutils examples illustrate some different needs.

If we do a good job here, it may serve as a template solution for this
problem elsewhere.  I see some systems migrate 32-bit time_t to 64-bit
time_t, and if not done carefully, that may introduce reliance on
undefined behaviour for years <1000 and >9999 when calling ctime that
wasn't there before.

> Perhaps we could a new module c_nstrftime, which acts like nstrftime
> but operates in the C locale. That should suffice to replace all uses
> of ctime relatively easily.

Yes, although I would prefer a wrapper to hide the complex strftime
format string needed.

How about the API below?

I'm not confident about the timezone handling: maybe it should set the
tzset variables?  And maybe a c_nctime_r would be useful to provide the
timezone TZ to use?  I'm also not certain about year 0 handling.

/* Convert TIMEP representing the number of seconds elapsed since epoch,
1970-01-01 00:00:00 +0000 (UTC), to a fixed locale-independent string
such as "Wed Jun 30 21:49:08 1993\n" using abbreviations for the days of
the week as "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", and "Sat" and
abbreviations for the months as "Jan", "Feb", "Mar", "Apr", "May",
"Jun", "Jul", "Aug", "Sep", "Oct", "Nov", and "Dec".  The function does
not set the external variables tzname, timezone or daylight, see
tzset(3).  The output is copied into STR which must have room for at
least LEN bytes.  For years 1000 to 9999 inclusive the needed length
will be 26 characters including the final NUL byte, but the required
length may be shorter for years < 1000 and larger for years > 9999.  The
years are not padded with whitespace or zeros, so valid outputs include
strings such as "Wed Jun 30 21:49:08 623\n" for years <1000 and for
years >9999 strings such as "Wed Jun 30 21:49:08 11147\n" and for
negative years strings such as "Wed Jun 30 21:49:08 -42\n".  The
preloptic Gregorian calendar is used for all years, to cover years
before the Gregorian calendar was adopted; and for years before 1 the
ISO 8601 approach to have years 2, 1, 0, -1, and so on is used instead
of having 2 BC, 1 BC, AD 1, AD 2.  If TIMEP cannot be converted into a
string of size LEN, NULL is returned and errno is set to an error,
otherwise on success STR is returned. */

char *c_ctime_r (time_t timep, char *str, size_t len);

/Simon

Attachment: signature.asc
Description: PGP signature

Reply via email to