-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. All the 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. Reported-by: Paul Eggert <eggert@xxxxxxxxxxx> Cc: DJ Delorie <dj@xxxxxxxxxx> Cc: Carlos O'Donell <carlos@xxxxxxxxxx> Cc: Xi Ruoyao <xry111@xxxxxxxxxxx> Cc: Vincent Lefevre <vincent@xxxxxxxxxx> Cc: GNU C Library <libc-alpha@xxxxxxxxxxxxxx> Signed-off-by: Alejandro Colomar <alx@xxxxxxxxxx> --- Hi! This patch only documents how to check for errors after mktime(3). It does not cover the corner cases reported by DJ. This patch should be uncontroversial. I'll rebase the other one after this. Cheers, Alex man/man3/ctime.3 | 100 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 1 deletion(-) diff --git a/man/man3/ctime.3 b/man/man3/ctime.3 index 5aec51b79..777e7d5b2 100644 --- a/man/man3/ctime.3 +++ b/man/man3/ctime.3 @@ -241,7 +241,10 @@ .SH RETURN VALUE 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 @@ -412,6 +415,101 @@ .SH NOTES object types may overwrite the information in any object of the same type pointed to by the value returned from any previous call to any of them." 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 if +.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 2024 03 26 02 17 53 \-1" ; +1679793473 +$ +.RB $\~ "./a.out 2024 10 29 02 17 53 \-1" ; +1698542273 +.RB $\~ "./a.out 2024 10 29 02 17 53 0" ; +1698542273 +.RB $\~ "./a.out 2024 10 29 02 17 53 1" ; +1698538673 +$ +.RB $\~ "./a.out 2024 02 29 12 00 00 \-1" ; +1677668400 +.EE +.SS Program source: mktime.c +\& +.\" SRC BEGIN (mktime.c) +.EX +#include <err.h> +#include <errno.h> +#include <limits.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +\& +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 = INT_MIN; + t = mktime(&tm); + if (tm.tm_wday == INT_MIN) + err(EXIT_FAILURE, "mktime"); +\& + printf("%jd\[rs]n", (intmax_t) t); + exit(EXIT_SUCCESS); +} +.EE +.\" SRC END .SH SEE ALSO .BR date (1), .BR gettimeofday (2), base-commit: 0813c125d8bf754c40015aa1b31f23e0650584ac -- 2.45.2
Attachment:
signature.asc
Description: PGP signature