commit e541b219854e6be90b5628f88cd62edb44c9e9f2 Author: Alejandro Colomar Date: Fri Aug 23 14:34:00 2024 +0200 ctime.3: Document how to check errors from mktime(3) -1 is a valid successful time_t, for one second before the Epoch. And mktime(3) is allowed (like most libc calls) to set errno on success. This makes it impossible to determine errors from the return value or errno. ISO C specifies that tp->tm_wday is unmodified after a failed call, and puts an example where this is used to determine errors. It is indeed the only way to check for errors from this call. Document this detail in the RETURN VALUE section, add a CAVEATS section that warns about this, and write an example program that shows how to properly call this function. Most code I've been able to find in several search engines either doesn't check for errors after mktime(3), or checks them incorrectly, so this documentation should help fix those. This is guaranteed since ISO C23 and POSIX.1-2024. Prior to those standards, there was no standard way to check for errors. However, there are no known implementations that do not conform to this. Link: Link: Link: Link: Link: Link: Reported-by: Paul Eggert Cc: Vincent Lefevre Cc: DJ Delorie Cc: Carlos O'Donell Cc: Xi Ruoyao Cc: Brian Inglis Cc: "Robert C. Seacord" Cc: Jens Gustedt Cc: Robert Elz Cc: Andrew Josey Cc: Geoff Clare Cc: Hans Ã…berg Cc: GNU C Library Cc: Austin Group Signed-off-by: Alejandro Colomar Conflicts: Minor wording differences diff -Nrup a/man3/ctime.3 b/man3/ctime.3 --- a/man3/ctime.3 2023-04-02 20:27:24.000000000 -0400 +++ b/man3/ctime.3 2025-06-18 09:39:54.782440669 -0400 @@ -247,7 +247,10 @@ expressed as a value of type On error, .BR mktime () returns the value -.IR "(time_t)\ \-1" . +.IR "(time_t)\ \-1" , +and leaves the +.I tm->tm_wday +member unmodified. The remaining functions return NULL on error. On error, .I errno @@ -400,6 +403,105 @@ a broken-down time structure and an arra Execution of any of the functions may overwrite the information returned in either of these objects by any of the other functions." This can occur in the glibc implementation. +.SH CAVEATS +.SS mktime() +.I (time_t) \-1 +can represent a valid time +(one second before the Epoch). +To determine whether +.BR mktime () +failed, +one must use the +.I tm->tm_wday +field. +See the example program in EXAMPLES. +.SH EXAMPLES +The following shell session shows sample runs of the program: +.P +.in +4n +.EX +.RB $\~ "TZ=UTC ./a.out 1969 12 31 23 59 59 0" ; +\-1 +$ +.RB $\~ "export TZ=Europe/Madrid" ; +$ +.RB $\~ "./a.out 2147483647 2147483647 00 00 00 00 -1" ; +a.out: mktime: Value too large for defined data type +$ +.RB $\~ "./a.out 2024 08 23 00 17 53 \-1" ; +1724365073 +.RB $\~ "./a.out 2024 08 23 00 17 53 0" ; +1724368673 +.RB $\~ "./a.out 2024 08 23 00 17 53 1" ; +1724365073 +$ +.RB $\~ "./a.out 2024 02 23 00 17 53 \-1" ; +1708643873 +.RB $\~ "./a.out 2024 02 23 00 17 53 0" ; +1708643873 +.RB $\~ "./a.out 2024 02 23 00 17 53 1" ; +1708640273 +$ +.RB $\~ "./a.out 2023 03 26 02 17 53 \-1" ; +1679793473 +$ +.RB $\~ "./a.out 2023 10 29 02 17 53 \-1" ; +1698542273 +.RB $\~ "./a.out 2023 10 29 02 17 53 0" ; +1698542273 +.RB $\~ "./a.out 2023 10 29 02 17 53 1" ; +1698538673 +$ +.RB $\~ "./a.out 2023 02 29 12 00 00 \-1" ; +1677668400 +.EE +.SS Program source: mktime.c +\& +.\" SRC BEGIN (mktime.c) +.EX +#include +#include +#include +#include +#include +\& +#define is_signed(T) ((T) \-1 < 1) +\& +int +main(int argc, char *argv[]) +{ + char **p; + time_t t; + struct tm tm; +\& + if (argc != 8) { + fprintf(stderr, "Usage: %s yyyy mm dd HH MM SS isdst\[rs]n", argv[0]); + exit(EXIT_FAILURE); + } +\& + p = &argv[1]; + tm.tm_year = atoi(*p++) \- 1900; + tm.tm_mon = atoi(*p++) \- 1; + tm.tm_mday = atoi(*p++); + tm.tm_hour = atoi(*p++); + tm.tm_min = atoi(*p++); + tm.tm_sec = atoi(*p++); + tm.tm_isdst = atoi(*p++); +\& + tm.tm_wday = \-1; + t = mktime(&tm); + if (tm.tm_wday == \-1) + err(EXIT_FAILURE, "mktime"); +\& + if (is_signed(time_t)) + printf("%jd\[rs]n", (intmax_t) t); + else + printf("%ju\[rs]n", (uintmax_t) t); +\& + exit(EXIT_SUCCESS); +} +.EE +.\" SRC END .SH SEE ALSO .BR date (1), .BR gettimeofday (2),