Another attempt below, with known open issues: 1) it seems something has to be said about tz variables, either the function "always sets" them, "never sets" them, or (in new text below) "may set" them depending on what other functions are called. Not optimal, but better than not documenting it. We can inspect the implementation later and change this too.
2) can we implement this in a way that it never fails? I still allow return==NULL to indicate errors below, until we can confirm that it is possible to implement this in a way that cannot fail. Returning "magic" values like "1970-01-01" seems worse than NULL to me, since then callers will need to do string comparisons to catch error situations. 3) below it says that nothing can be assumed about thread safety (beyond that it depend on an environment variable), which seems a bit sub-optimal, but let's see how this ends up being implemented and if we can say something better. Saying that nothing can be assumed about thread safety is better than not saying anything, IMO. 4) Bruno suggested not documenting anything about week/month names, what calendar is used, the year < 1 handling or expected output string lengths -- I tend to disagree: at least my goal is for this function to be a drop-in well-defined superset for ctime. For ctime those properties are either specified and documented (and then we want to document that this function is compatible) or left undefined/undocumented (and then we want to provide well-defined portable documented semantics). The later problem with ctime seems to be the reason we need to introduce a safer variant in the first place. 5) Naming. I'm okay with 'safer_ctime' but still think it is ugly. Bruno's suggestion of 'c_strnl_from_time' sounds better to me, even though it is a mouthful. How about 'strtime.h' and 'strctime'? If there is a need to offer a drop-in for asctime, then 'strasctime' is relevant. This seems more in line with existing C stdlib functions. /Simon /* strtime.h -- safe versions of time-related string functions. Copyright (C) 2024 FSF Authors: Paul Eggert, Bruno Haible, Simon Josefsson License: LGPL-2+ */ #include <stdint.h> #include <time.h> /* This evaluates to 35 on typical machines today, and will grow automatically if time_t gets wider - it could even exceed 70 if needed. 7 = floor(log10(60*60*24*365)). */ #define STRCTIME_BUFSIZE \ (sizeof "Wed Jun 30 21:49:08 \n" \ + INT_STRLEN_BOUND (time_t) - 7) /* Convert WHEN representing the number of seconds related to epoch, 1970-01-01 00:00:00 +0000 (UTC), to a fixed locale-independent NUL-terminated string such as "Wed Jun 30 21:49:08 1993\n\0", relative to the user's specified timezone (TZ environment variable), 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 may set the external variables tzname, timezone, and daylight (see tzset(3)) with information about the current timezone. The output is copied into STR which should have room for at least STRCTIME_BUFSIZE bytes. If STR is NULL, a pointer to a global statically pre-allocated buffer of size STRCTIME_BUFSIZE is used instead. For years 1000 to 9999 inclusive the output string length is 26 characters including the final NUL byte. The string length may be shorter for some years before 1000, and larger for years after 9999 or before -999. The years are not padded with whitespace or zeros, so valid outputs include strings "Wed Jun 30 21:49:08 623\n" and "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. On systems with a 64-bit time_t type, the year value may be large as in strings looking like "Sun Sep 16 01:03:52 -292471206706\n\0", and future systems with larger time_t types may lead to even longer strings. If WHEN cannot be converted into a string, NULL is returned and errno is set to an error, otherwise on success STR (or a pointer to the global buffer) is returned. The result depends on the environment variable TZ; no further Thread safety attributes can be reliably assumed about this function. */ char *strctime (time_t when, char *str);
signature.asc
Description: PGP signature