174 lines
5.2 KiB
Diff
174 lines
5.2 KiB
Diff
commit e541b219854e6be90b5628f88cd62edb44c9e9f2
|
|
Author: Alejandro Colomar <alx@kernel.org>
|
|
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: <https://lore.kernel.org/linux-man/20240823131024.GD2713@cventin.lip.ens-lyon.fr/T/#t>
|
|
Link: <https://lore.kernel.org/linux-man/6un6baaq5tez23irtycuvzqtuh7a4sdrf2px7tnyb3y6iqoxmq@2ofln4cd27ep/T/#t>
|
|
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3147.txt>
|
|
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3148.doc>
|
|
Link: <https://austingroupbugs.net/view.php?id=1614>
|
|
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3220.pdf#subsubsection.7.29.2.3>
|
|
Reported-by: Paul Eggert <eggert@cs.ucla.edu>
|
|
Cc: Vincent Lefevre <vincent@vinc17.net>
|
|
Cc: DJ Delorie <dj@redhat.com>
|
|
Cc: Carlos O'Donell <carlos@redhat.com>
|
|
Cc: Xi Ruoyao <xry111@xry111.site>
|
|
Cc: Brian Inglis <Brian.Inglis@SystematicSW.ab.ca>
|
|
Cc: "Robert C. Seacord" <rcseacord@gmail.com>
|
|
Cc: Jens Gustedt <jens.gustedt@inria.fr>
|
|
Cc: Robert Elz <kre@munnari.oz.au>
|
|
Cc: Andrew Josey <ajosey@opengroup.org>
|
|
Cc: Geoff Clare <gwc@opengroup.org>
|
|
Cc: Hans Åberg <haberg-1@telia.com>
|
|
Cc: GNU C Library <libc-alpha@sourceware.org>
|
|
Cc: Austin Group <austin-group-l@opengroup.org>
|
|
Signed-off-by: Alejandro Colomar <alx@kernel.org>
|
|
|
|
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 <err.h>
|
|
+#include <stdint.h>
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <time.h>
|
|
+\&
|
|
+#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),
|