* [PATCH v4] ctime.3: Document how to detect invalid or ambiguous times
@ 2024-08-23 23:11 Alejandro Colomar
[not found] ` <xned6jlywd.fsf@greed.delorie.com>
0 siblings, 1 reply; 25+ messages in thread
From: Alejandro Colomar @ 2024-08-23 23:11 UTC (permalink / raw)
To: Alejandro Colomar; +Cc: linux-man, DJ Delorie, Carlos O'Donell, Paul Eggert
[-- Attachment #1: Type: text/plain, Size: 5179 bytes --]
This example documents the corner cases of mktime(3), such as what
happens during DST transitions, and other jumps in the calendar.
Link: <https://www.redhat.com/en/blog/brief-history-mktime>
Reported-by: DJ Delorie <dj@redhat.com>
Cc: Carlos O'Donell <carlos@redhat.com>
Cc: Paul Eggert <eggert@cs.ucla.edu>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
Hi DJ, Paul,
I've rebased on top of the patch from today which added an example
which showed how to check for errors after mktime(3).
This example extends it to also detect non-error corner-case conditions
that are not always wanted: invalid times, and ambiguous times.
It also documents lightly in CAVEATS that the result is unspecified in
any such call, without much details (because it's just unspecified).
DJ, I expect that the wrapper my_mktime(), which is itself a conforming
implementation of mktime(3), is what you were looking for.
Have a lovely night!
Alex
Range-diff against v3:
1: e9e31a505 < -: --------- ctime.3: EXAMPLES: Add example program
-: --------- > 1: b7ed55965 ctime.3: Document how to detect invalid or ambiguous times
man/man3/ctime.3 | 93 +++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 92 insertions(+), 1 deletion(-)
diff --git a/man/man3/ctime.3 b/man/man3/ctime.3
index 0ad2b530f..934da149e 100644
--- a/man/man3/ctime.3
+++ b/man/man3/ctime.3
@@ -427,7 +427,30 @@ .SS mktime()
.I tm->tm_wday
field.
See the example program in EXAMPLES.
+.P
+Passing an invalid time to
+.BR mktime ()
+or an invalid
+.I tm->tm_isdst
+value
+yields an unspecified result.
+Also,
+passing the value
+.I \-1
+in
+.I tm->tm_isdst
+will result in an ambiguous time during some DST transitions,
+which will also yield an unspecified result.
+See the example program in EXAMPLES.
.SH EXAMPLES
+The program below defines a wrapper that
+allows detecting invalid and ambiguous times,
+with
+.B EINVAL
+and
+.BR ENOTUNIQ ,
+respectively.
+.P
The following shell session shows sample runs of the program:
.P
.in +4n
@@ -443,6 +466,7 @@ .SH EXAMPLES
.RB $\~ "./a.out 2024 08 23 00 17 53 \-1" ;
1724365073
.RB $\~ "./a.out 2024 08 23 00 17 53 0" ;
+a.out: mktime: Invalid argument
1724368673
.RB $\~ "./a.out 2024 08 23 00 17 53 1" ;
1724365073
@@ -452,12 +476,15 @@ .SH EXAMPLES
.RB $\~ "./a.out 2024 02 23 00 17 53 0" ;
1708643873
.RB $\~ "./a.out 2024 02 23 00 17 53 1" ;
+a.out: mktime: Invalid argument
1708640273
$
.RB $\~ "./a.out 2023 03 26 02 17 53 \-1" ;
+a.out: mktime: Invalid argument
1679793473
$
.RB $\~ "./a.out 2023 10 29 02 17 53 \-1" ;
+a.out: mktime: Name not unique on network
1698542273
.RB $\~ "./a.out 2023 10 29 02 17 53 0" ;
1698542273
@@ -465,6 +492,7 @@ .SH EXAMPLES
1698538673
$
.RB $\~ "./a.out 2023 02 29 12 00 00 \-1" ;
+a.out: mktime: Invalid argument
1677668400
.EE
.SS Program source: mktime.c
@@ -472,13 +500,17 @@ .SS Program source: mktime.c
.\" SRC BEGIN (mktime.c)
.EX
#include <err.h>
+#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <time.h>
\&
#define is_signed(T) ((T) \-1 < 1)
\&
+time_t my_mktime(struct tm *tp);
+\&
int
main(int argc, char *argv[])
{
@@ -500,10 +532,13 @@ .SS Program source: mktime.c
tm.tm_sec = atoi(*p++);
tm.tm_isdst = atoi(*p++);
\&
+ errno = 0;
tm.tm_wday = \-1;
- t = mktime(&tm);
+ t = my_mktime(&tm);
if (tm.tm_wday == \-1)
err(EXIT_FAILURE, "mktime");
+ if (errno == EINVAL || errno == ENOTUNIQ)
+ warn("mktime");
\&
if (is_signed(time_t))
printf("%jd\[rs]n", (intmax_t) t);
@@ -512,6 +547,62 @@ .SS Program source: mktime.c
\&
exit(EXIT_SUCCESS);
}
+\&
+time_t
+my_mktime(struct tm *tp)
+{
+ int e, isdst;
+ time_t t;
+ struct tm tm;
+ unsigned char wday[sizeof(tp\->tm_wday)];
+\&
+ e = errno;
+\&
+ tm = *tp;
+ isdst = tp\->tm_isdst;
+\&
+ memcpy(wday, &tp\->tm_wday, sizeof(wday));
+ tp\->tm_wday = \-1;
+ t = mktime(tp);
+ if (tp\->tm_wday == \-1) {
+ memcpy(&tp\->tm_wday, wday, sizeof(wday));
+ return \-1;
+ }
+\&
+ if (isdst == \-1)
+ tm.tm_isdst = tp\->tm_isdst;
+\&
+ if ( tm.tm_sec != tp\->tm_sec
+ || tm.tm_min != tp\->tm_min
+ || tm.tm_hour != tp\->tm_hour
+ || tm.tm_mday != tp\->tm_mday
+ || tm.tm_mon != tp\->tm_mon
+ || tm.tm_year != tp\->tm_year
+ || tm.tm_isdst != tp\->tm_isdst)
+ {
+ errno = EINVAL;
+ return t;
+ }
+\&
+ if (isdst != \-1)
+ goto out;
+\&
+ tm = *tp;
+ tm.tm_isdst = !tm.tm_isdst;
+\&
+ tm.tm_wday = \-1;
+ mktime(&tm);
+ if (tm.tm_wday == \-1)
+ goto out;
+\&
+ if (tm.tm_isdst != tp\->tm_isdst) {
+ errno = ENOTUNIQ;
+ return t;
+ }
+out:
+ errno = e;
+ return t;
+}
.EE
.\" SRC END
.SH SEE ALSO
base-commit: 6a7f1461b0e5474d50ef1920558dec103c0c058f
--
2.45.2
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply related [flat|nested] 25+ messages in thread[parent not found: <xned6jlywd.fsf@greed.delorie.com>]
* [PATCH v3] ctime.3: EXAMPLES: Add example program [not found] ` <xned6jlywd.fsf@greed.delorie.com> @ 2024-08-22 23:49 ` Alejandro Colomar 2024-08-23 4:57 ` Paul Eggert 2024-08-24 8:46 ` [PATCH v5] ctime.3: Document how to detect invalid or ambiguous times Alejandro Colomar 1 sibling, 1 reply; 25+ messages in thread From: Alejandro Colomar @ 2024-08-22 23:49 UTC (permalink / raw) To: Alejandro Colomar, DJ Delorie, Paul Eggert; +Cc: linux-man, carlos [-- Attachment #1: Type: text/plain, Size: 8451 bytes --] This example documents the corner cases of mktime(3), such as what happens during DST transitions, and other jumps in the calendar. Link: <https://www.redhat.com/en/blog/brief-history-mktime> Reported-by: DJ Delorie <dj@redhat.com> Cc: Paul Eggert <eggert@cs.ucla.edu> Signed-off-by: Alejandro Colomar <alx@kernel.org> --- Hi DJ, Paul! Below is the rendered text. I've tested this program with several "weird" times, and it all makes sense. Please review. I call it v3, since it supersedes DJ's patches. Have a lovely night! Alex EXAMPLES Passing an invalid time to mktime() or an invalid tm‐>tm_isdst value yields unspecified results. Also, passing the value -1 in tm‐>tm_isdst will result in an ambiguous time during some DST transitions, which will also yield an unspecified result. The program below uses a wrapper that allows detecting invalid and ambiguous times, with EINVAL and ENOTUNIQ, respectively. The following shell session shows sample runs of the program: $ export TZ=Europe/Madrid; $ $ ./a.out 2024 08 23 00 17 53 -1; 1724365073 $ ./a.out 2024 08 23 00 17 53 0; a.out: mktime: Invalid argument 1724368673 $ ./a.out 2024 08 23 00 17 53 1; 1724365073 $ $ ./a.out 2024 02 23 00 17 53 -1; 1708643873 $ ./a.out 2024 02 23 00 17 53 0; 1708643873 $ ./a.out 2024 02 23 00 17 53 1; a.out: mktime: Invalid argument 1708640273 $ $ ./a.out 2024 03 26 02 17 53 -1; a.out: mktime: Invalid argument 1679793473 $ $ ./a.out 2024 10 29 02 17 53 -1; a.out: mktime: Name not unique on network 1698542273 $ ./a.out 2024 10 29 02 17 53 0; 1698542273 $ ./a.out 2024 10 29 02 17 53 1; 1698538673 $ $ ./a.out 2024 02 29 12 00 00 -1; a.out: mktime: Invalid argument 1677668400 Program source: mktime.c #include <err.h> #include <errno.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <time.h> time_t my_mktime(struct tm *tp); 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\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++); errno = 0; t = my_mktime(&tm); if (errno == EOVERFLOW) err(EXIT_FAILURE, "mktime"); if (errno == EINVAL || errno == ENOTUNIQ) warn("mktime"); printf("%ju\n", (uintmax_t) t); exit(EXIT_SUCCESS); } time_t my_mktime(struct tm *tp) { int e, isdst; time_t t; struct tm tm; e = errno; errno = 0; tm = *tp; isdst = tp->tm_isdst; t = mktime(tp); if (t == -1 && errno == EOVERFLOW) return -1; if (isdst == -1) tm.tm_isdst = tp->tm_isdst; if ( tm.tm_sec != tp->tm_sec || tm.tm_min != tp->tm_min || tm.tm_hour != tp->tm_hour || tm.tm_mday != tp->tm_mday || tm.tm_mon != tp->tm_mon || tm.tm_year != tp->tm_year || tm.tm_isdst != tp->tm_isdst) { errno = EINVAL; return t; } if (isdst != -1) goto out; tm = *tp; tm.tm_isdst = !tm.tm_isdst; if (mktime(&tm) == -1 && errno == EOVERFLOW) goto out; if (tm.tm_isdst != tp->tm_isdst) { errno = ENOTUNIQ; return t; } out: errno = e; return t; } man/man3/ctime.3 | 157 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) diff --git a/man/man3/ctime.3 b/man/man3/ctime.3 index 5aec51b79..5ab881978 100644 --- a/man/man3/ctime.3 +++ b/man/man3/ctime.3 @@ -412,6 +412,163 @@ .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 EXAMPLES +Passing an invalid time to +.BR mktime () +or an invalid +.I tm->tm_isdst +value +yields unspecified results. +Also, +passing the value +.I \-1 +in +.I tm->tm_isdst +will result in an ambiguous time during some DST transitions, +which will also yield an unspecified result. +.P +The program below uses a wrapper that +allows detecting invalid and ambiguous times, +with +.B EINVAL +and +.BR ENOTUNIQ , +respectively. +.P +The following shell session shows sample runs of the program: +.P +.in +4n +.EX +.RB $\~ "export TZ=Europe/Madrid" ; +$ +.RB $\~ "./a.out 2024 08 23 00 17 53 \-1" ; +1724365073 +.RB $\~ "./a.out 2024 08 23 00 17 53 0" ; +a.out: mktime: Invalid argument +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" ; +a.out: mktime: Invalid argument +1708640273 +$ +.RB $\~ "./a.out 2024 03 26 02 17 53 \-1" ; +a.out: mktime: Invalid argument +1679793473 +$ +.RB $\~ "./a.out 2024 10 29 02 17 53 \-1" ; +a.out: mktime: Name not unique on network +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" ; +a.out: mktime: Invalid argument +1677668400 +.EE +.SS Program source: mktime.c +\& +.\" SRC BEGIN (mktime.c) +.EX +#include <err.h> +#include <errno.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +\& +time_t my_mktime(struct tm *tp); +\& +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++); +\& + errno = 0; + t = my_mktime(&tm); + if (errno == EOVERFLOW) + err(EXIT_FAILURE, "mktime"); + if (errno == EINVAL || errno == ENOTUNIQ) + warn("mktime"); +\& + printf("%ju\[rs]n", (uintmax_t) t); + exit(EXIT_SUCCESS); +} +\& +time_t +my_mktime(struct tm *tp) +{ + int e, isdst; + time_t t; + struct tm tm; +\& + e = errno; + errno = 0; +\& + tm = *tp; + isdst = tp\->tm_isdst; +\& + t = mktime(tp); + if (t == \-1 && errno == EOVERFLOW) + return \-1; +\& + if (isdst == \-1) + tm.tm_isdst = tp\->tm_isdst; +\& + if ( tm.tm_sec != tp\->tm_sec + || tm.tm_min != tp\->tm_min + || tm.tm_hour != tp\->tm_hour + || tm.tm_mday != tp\->tm_mday + || tm.tm_mon != tp\->tm_mon + || tm.tm_year != tp\->tm_year + || tm.tm_isdst != tp\->tm_isdst) + { + errno = EINVAL; + return t; + } +\& + if (isdst != \-1) + goto out; +\& + tm = *tp; + tm.tm_isdst = !tm.tm_isdst; +\& + if (mktime(&tm) == \-1 && errno == EOVERFLOW) + goto out; +\& + if (tm.tm_isdst != tp\->tm_isdst) { + errno = ENOTUNIQ; + return t; + } +out: + errno = e; + return t; +} +.EE +.\" SRC END .SH SEE ALSO .BR date (1), .BR gettimeofday (2), base-commit: 0813c125d8bf754c40015aa1b31f23e0650584ac -- 2.45.2 [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH v3] ctime.3: EXAMPLES: Add example program 2024-08-22 23:49 ` [PATCH v3] ctime.3: EXAMPLES: Add example program Alejandro Colomar @ 2024-08-23 4:57 ` Paul Eggert 2024-08-23 7:02 ` Alejandro Colomar 0 siblings, 1 reply; 25+ messages in thread From: Paul Eggert @ 2024-08-23 4:57 UTC (permalink / raw) To: Alejandro Colomar, DJ Delorie; +Cc: linux-man, carlos On 2024-08-22 16:49, Alejandro Colomar wrote: > t = mktime(tp); > if (t == -1 && errno == EOVERFLOW) > return -1; This isn't right, for the same reason similar code wasn't right earlier. A successful call to mktime can return -1 and set errno to whatever value it likes. This is just the first problem I found with the code (and I found it quickly because I remembered the earlier problem). I would expect there to be others. How about if we omit the sample code and make the minimal changes I suggested earlier? ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v3] ctime.3: EXAMPLES: Add example program 2024-08-23 4:57 ` Paul Eggert @ 2024-08-23 7:02 ` Alejandro Colomar 2024-08-23 7:26 ` Xi Ruoyao 0 siblings, 1 reply; 25+ messages in thread From: Alejandro Colomar @ 2024-08-23 7:02 UTC (permalink / raw) To: Paul Eggert, libc-alpha; +Cc: DJ Delorie, linux-man, carlos [-- Attachment #1: Type: text/plain, Size: 1690 bytes --] On Thu, Aug 22, 2024 at 09:57:39PM GMT, Paul Eggert wrote: > On 2024-08-22 16:49, Alejandro Colomar wrote: > > t = mktime(tp); > > if (t == -1 && errno == EOVERFLOW) > > return -1; > > This isn't right, for the same reason similar code wasn't right earlier. A > successful call to mktime can return -1 and set errno to whatever value it > likes. Is mktime(3) allowed to return -1 and set EOVERFLOW on a successful call? RETURN VALUE The mktime() function shall return the specified time since the Epoch encoded as a value of type time_t. If the time since the Epoch cannot be represented, the function shall return the value (time_t)-1 and set errno to indicate the error. ERRORS The mktime() function shall fail if: EOVERFLOW The result cannot be represented. The following sections are informative. Then I think the API is completely broken. How should we check for errors after a mktime(3) call? If this is so, let me file a glibc bug requesting a fix of the API, adding a promise that on success, errno will remain unset. > This is just the first problem I found with the code (and I found it quickly > because I remembered the earlier problem). I would expect there to be > others. > > How about if we omit the sample code and make the minimal changes I > suggested earlier? Because I'm being very careful writing that code, and still I'm having trouble doing that, I think we must provide some example of a correct call, to prevent many other programmers from doing it wrong. Cheers, Alex -- <https://www.alejandro-colomar.es/> [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v3] ctime.3: EXAMPLES: Add example program 2024-08-23 7:02 ` Alejandro Colomar @ 2024-08-23 7:26 ` Xi Ruoyao 2024-08-23 7:57 ` Vincent Lefevre 2024-08-23 12:28 ` Alejandro Colomar 0 siblings, 2 replies; 25+ messages in thread From: Xi Ruoyao @ 2024-08-23 7:26 UTC (permalink / raw) To: Alejandro Colomar, Paul Eggert, libc-alpha; +Cc: DJ Delorie, linux-man, carlos On Fri, 2024-08-23 at 09:02 +0200, Alejandro Colomar wrote: > Is mktime(3) allowed to return -1 and set EOVERFLOW on a successful > call? > > RETURN VALUE > The mktime() function shall return the specified time since the > Epoch encoded as a value of type time_t. If the time since the > Epoch cannot be represented, the function shall return the value > (time_t)-1 and set errno to indicate the error. For mktime the standard only says "return (time_t)-1." It does not mention errno at all. And the standard also says: The value of errno may be set to nonzero by a library function call whether or not there is an error, provided the use of errno is not documented in the description of the function in this document. > Then I think the API is completely broken. How should we check for > errors after a mktime(3) call? Maybe, special case if tm contains Dec 31 1969 23:59:59 UTC... But it's just stupid. > If this is so, let me file a glibc bug requesting a fix of the API, > adding a promise that on success, errno will remain unset. It's a bug in the standard, not glibc. And the standard has deprecated it anyway. https://www.open-std.org/JTC1/SC22/WG14/www/docs/n2566.pdf > > How about if we omit the sample code and make the minimal changes I > > suggested earlier? > > Because I'm being very careful writing that code, and still I'm having > trouble doing that, I think we must provide some example of a correct > call, to prevent many other programmers from doing it wrong. So IMO you should just say "the interface is deprecated, do not use it in any new code." -- Xi Ruoyao <xry111@xry111.site> School of Aerospace Science and Technology, Xidian University ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v3] ctime.3: EXAMPLES: Add example program 2024-08-23 7:26 ` Xi Ruoyao @ 2024-08-23 7:57 ` Vincent Lefevre 2024-08-23 12:28 ` Alejandro Colomar 1 sibling, 0 replies; 25+ messages in thread From: Vincent Lefevre @ 2024-08-23 7:57 UTC (permalink / raw) To: Xi Ruoyao Cc: Alejandro Colomar, Paul Eggert, libc-alpha, DJ Delorie, linux-man, carlos On 2024-08-23 15:26:04 +0800, Xi Ruoyao wrote: > On Fri, 2024-08-23 at 09:02 +0200, Alejandro Colomar wrote: > > Is mktime(3) allowed to return -1 and set EOVERFLOW on a successful > > call? > > > > RETURN VALUE > > The mktime() function shall return the specified time since the > > Epoch encoded as a value of type time_t. If the time since the > > Epoch cannot be represented, the function shall return the value > > (time_t)-1 and set errno to indicate the error. > > For mktime the standard only says "return (time_t)-1." It does not > mention errno at all. And the standard also says: > > The value of errno may be set to nonzero by a library function call > whether or not there is an error, provided the use of errno is not > documented in the description of the function in this document. > > > Then I think the API is completely broken. How should we check for > > errors after a mktime(3) call? > > Maybe, special case if tm contains Dec 31 1969 23:59:59 UTC... But it's > just stupid. > > > If this is so, let me file a glibc bug requesting a fix of the API, > > adding a promise that on success, errno will remain unset. > > It's a bug in the standard, not glibc. And the standard has deprecated > it anyway. > > https://www.open-std.org/JTC1/SC22/WG14/www/docs/n2566.pdf I can see only asctime and ctime mentioned there, not mktime. So mktime isn't deprecated, is it? -- Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/> 100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/> Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon) ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v3] ctime.3: EXAMPLES: Add example program 2024-08-23 7:26 ` Xi Ruoyao 2024-08-23 7:57 ` Vincent Lefevre @ 2024-08-23 12:28 ` Alejandro Colomar 2024-08-23 12:28 ` Xi Ruoyao 2024-08-23 12:53 ` Vincent Lefevre 1 sibling, 2 replies; 25+ messages in thread From: Alejandro Colomar @ 2024-08-23 12:28 UTC (permalink / raw) To: Xi Ruoyao; +Cc: Paul Eggert, libc-alpha, DJ Delorie, linux-man, carlos [-- Attachment #1: Type: text/plain, Size: 3055 bytes --] Hi Xi, On Fri, Aug 23, 2024 at 03:26:04PM GMT, Xi Ruoyao wrote: > On Fri, 2024-08-23 at 09:02 +0200, Alejandro Colomar wrote: > > Is mktime(3) allowed to return -1 and set EOVERFLOW on a successful > > call? > > > > RETURN VALUE > > The mktime() function shall return the specified time since the > > Epoch encoded as a value of type time_t. If the time since the > > Epoch cannot be represented, the function shall return the value > > (time_t)-1 and set errno to indicate the error. > > For mktime the standard only says "return (time_t)-1." It does not > mention errno at all. And the standard also says: > > The value of errno may be set to nonzero by a library function call > whether or not there is an error, provided the use of errno is not > documented in the description of the function in this document. > > > Then I think the API is completely broken. How should we check for > > errors after a mktime(3) call? > > Maybe, special case if tm contains Dec 31 1969 23:59:59 UTC... But it's > just stupid. > > > If this is so, let me file a glibc bug requesting a fix of the API, > > adding a promise that on success, errno will remain unset. > > It's a bug in the standard, not glibc. And the standard has deprecated > it anyway. > > https://www.open-std.org/JTC1/SC22/WG14/www/docs/n2566.pdf The standard has only codified existing practice regarding mktime(3). mktime(3) was already standardized in POSIX.1-1988 before ANSI C. And considering that POSIX usually just codifies existing practice without inventions, the blame is on the implementations. So, yes, all implementations and the standard seem sub-par. Although, I've been checking ISO C after your comments, and I found an interesting specification in ISO C that is not present in POSIX, and is also missing in the Linux manual page: tm_wday is guaranteed to be left unmodified on a failed call. This provides a way to determine if the call failed. Indeed, this is the only way to determine if the call failed: tm.tm_wday = INT_MAX; mktime(&tm); if (tm.tm_wday == INT_MAX) err(1, "mktime"); I'll add this to the manual page. This makes mktime(3) not broken. Although it is still quite obscure. Every call that I've seen in a search either don't check for errors, or check them incorrectly. A better API is definitely possible, and it would even keep backwards compatibility. > > > > How about if we omit the sample code and make the minimal changes I > > > suggested earlier? > > > > Because I'm being very careful writing that code, and still I'm having > > trouble doing that, I think we must provide some example of a correct > > call, to prevent many other programmers from doing it wrong. > > So IMO you should just say "the interface is deprecated, do not use it > in any new code." mktime(3) is not deprecated, as Vincent pointed out. Have a lovely day! Alex -- <https://www.alejandro-colomar.es/> [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v3] ctime.3: EXAMPLES: Add example program 2024-08-23 12:28 ` Alejandro Colomar @ 2024-08-23 12:28 ` Xi Ruoyao 2024-08-23 12:53 ` Vincent Lefevre 1 sibling, 0 replies; 25+ messages in thread From: Xi Ruoyao @ 2024-08-23 12:28 UTC (permalink / raw) To: Alejandro Colomar; +Cc: Paul Eggert, libc-alpha, DJ Delorie, linux-man, carlos On Fri, 2024-08-23 at 14:28 +0200, Alejandro Colomar wrote: > > > Because I'm being very careful writing that code, and still I'm having > > > trouble doing that, I think we must provide some example of a correct > > > call, to prevent many other programmers from doing it wrong. > > > > So IMO you should just say "the interface is deprecated, do not use it > > in any new code." > > mktime(3) is not deprecated, as Vincent pointed out. I must be lacking sleeping time recent days :(. -- Xi Ruoyao <xry111@xry111.site> School of Aerospace Science and Technology, Xidian University ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v3] ctime.3: EXAMPLES: Add example program 2024-08-23 12:28 ` Alejandro Colomar 2024-08-23 12:28 ` Xi Ruoyao @ 2024-08-23 12:53 ` Vincent Lefevre 2024-08-23 13:12 ` Alejandro Colomar 1 sibling, 1 reply; 25+ messages in thread From: Vincent Lefevre @ 2024-08-23 12:53 UTC (permalink / raw) To: Alejandro Colomar Cc: Xi Ruoyao, Paul Eggert, libc-alpha, DJ Delorie, linux-man, carlos On 2024-08-23 14:28:13 +0200, Alejandro Colomar wrote: [about mktime] > tm_wday is guaranteed to be left unmodified on a failed call. Where did you see that? I cannot see any guarantee in case of a failed call, so that I would say that tm_wday could have been modified, e.g. if the values are set before checking whether the calendar time can be represented. > This provides a way to determine if the call failed. The example in C17 does not use the above claim that "tm_wday is guaranteed to be left unmodified on a failed call" to determine whether the call failed. Instead, it uses if (mktime(&time_str) == (time_t)(-1)) which is not 100% correct, since -1 can be a valid value (as already noticed). > Indeed, this is the only way to determine if the call failed: > > tm.tm_wday = INT_MAX; > mktime(&tm); > if (tm.tm_wday == INT_MAX) > err(1, "mktime"); Because of my above remark, I think that a mktime(&tm) == (time_t)(-1) test is needed *in addition to* the tm.tm_wday == INT_MAX test. -- Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/> 100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/> Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon) ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v3] ctime.3: EXAMPLES: Add example program 2024-08-23 12:53 ` Vincent Lefevre @ 2024-08-23 13:12 ` Alejandro Colomar 2024-08-23 13:54 ` Vincent Lefevre 2024-08-23 14:04 ` Brian Inglis 0 siblings, 2 replies; 25+ messages in thread From: Alejandro Colomar @ 2024-08-23 13:12 UTC (permalink / raw) To: Vincent Lefevre, Xi Ruoyao, Paul Eggert, libc-alpha, DJ Delorie, linux-man, carlos Cc: Robert C. Seacord, Jens Gustedt [-- Attachment #1: Type: text/plain, Size: 2495 bytes --] Hi Vincent, On Fri, Aug 23, 2024 at 02:53:13PM GMT, Vincent Lefevre wrote: > On 2024-08-23 14:28:13 +0200, Alejandro Colomar wrote: > [about mktime] > > tm_wday is guaranteed to be left unmodified on a failed call. > > Where did you see that? Hmmm, it seems a novelty of C23. I don't find it in C11. Here's the text in C23: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3220.pdf#subsubsection.7.29.2.3> If the calendar time cannot be represented in the time_t encoding used for the return value or the value to be returned in the tm_year component of the structure pointed to by timeptr cannot be represented as an int, the function returns the value (time_t)(-1) and does not change the value of the tm_wday component of the structure. And the example code has also been modified in C23 to use this feature: static const char *const wday[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "-unknown-" }; ... time_str.tm_wday = 7; mktime(&time_str); printf("%s\n", wday[time_str.tm_wday]); > I cannot see any guarantee in case of a failed call, so that I would > say that tm_wday could have been modified, e.g. if the values are > set before checking whether the calendar time can be represented. Looking at the WG14 document logs, it seems it was added in n3147: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3147.txt> I've CCed Robert (author of that paper) and Jens (proposed other changes to mktime(3) recently), which may know what was discussed there. I assume they checked that this is true in all existing implementations, but that's just my assumption, so maybe they can say something. > > This provides a way to determine if the call failed. > > The example in C17 does not use the above claim that "tm_wday is > guaranteed to be left unmodified on a failed call" to determine > whether the call failed. Instead, it uses > > if (mktime(&time_str) == (time_t)(-1)) > > which is not 100% correct, since -1 can be a valid value (as already > noticed). > > > Indeed, this is the only way to determine if the call failed: > > > > tm.tm_wday = INT_MAX; > > mktime(&tm); > > if (tm.tm_wday == INT_MAX) > > err(1, "mktime"); > > Because of my above remark, I think that a mktime(&tm) == (time_t)(-1) > test is needed *in addition to* the tm.tm_wday == INT_MAX test. Have a lovely day! Alex -- <https://www.alejandro-colomar.es/> [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v3] ctime.3: EXAMPLES: Add example program 2024-08-23 13:12 ` Alejandro Colomar @ 2024-08-23 13:54 ` Vincent Lefevre 2024-08-23 14:18 ` Alejandro Colomar 2024-08-23 14:04 ` Brian Inglis 1 sibling, 1 reply; 25+ messages in thread From: Vincent Lefevre @ 2024-08-23 13:54 UTC (permalink / raw) To: Alejandro Colomar Cc: Xi Ruoyao, Paul Eggert, libc-alpha, DJ Delorie, linux-man, carlos, Robert C. Seacord, Jens Gustedt On 2024-08-23 15:12:16 +0200, Alejandro Colomar wrote: > Looking at the WG14 document logs, it seems it was added in n3147: > <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3147.txt> Thanks for the reference. Additional details can be found in CD2 ballot at https://open-std.org/JTC1/SC22/WG14/www/docs/n3148.doc which references the POSIX bug https://austingroupbugs.net/view.php?id=1614 where I can see at the end: On page 1332 line 44348 section mktime(), change: if (mktime(&time_str) == -1) to: time_str.tm_wday = -1; if (mktime(&time_str) == (time_t)-1 && time_str.tm_wday == -1) This is the test I suggested: a check that mktime() returns -1, and since it can be a valid value, a second test on tm_wday (where the input, which is ignored, has an invalid value such as -1 here, or INT_MAX in your case; note that -1 may be more efficient with some processors, and shorter to write). -- Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/> 100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/> Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon) ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v3] ctime.3: EXAMPLES: Add example program 2024-08-23 13:54 ` Vincent Lefevre @ 2024-08-23 14:18 ` Alejandro Colomar 2024-08-23 15:26 ` Vincent Lefevre 0 siblings, 1 reply; 25+ messages in thread From: Alejandro Colomar @ 2024-08-23 14:18 UTC (permalink / raw) To: Vincent Lefevre, Xi Ruoyao, Paul Eggert, libc-alpha, DJ Delorie, linux-man, carlos, Robert C. Seacord, Jens Gustedt [-- Attachment #1: Type: text/plain, Size: 2519 bytes --] Hi Vincent, On Fri, Aug 23, 2024 at 03:54:49PM GMT, Vincent Lefevre wrote: > On 2024-08-23 15:12:16 +0200, Alejandro Colomar wrote: > > Looking at the WG14 document logs, it seems it was added in n3147: > > <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3147.txt> > > Thanks for the reference. Additional details can be found > in CD2 ballot at > > https://open-std.org/JTC1/SC22/WG14/www/docs/n3148.doc It's interesting that WG14 claims that they're not aware of any existing implementations that would modify tm_wday on failure. Although it's weird, because WG14 attributes that claim to the Austin Group, and > > which references the POSIX bug > > https://austingroupbugs.net/view.php?id=1614 I don't see any discussion about tm_wday in that Austin Group bug. :| Maybe it happened in a mailing list or elsewhere. Anyway, let's trust that claim. (If any implementation does not conform, at least it should be feasible to fix that implementation to conform.) > where I can see at the end: > > On page 1332 line 44348 section mktime(), change: > > if (mktime(&time_str) == -1) > > to: > > time_str.tm_wday = -1; > if (mktime(&time_str) == (time_t)-1 && time_str.tm_wday == -1) Yep, they do that change, although I haven't been able to find a discussion that justifies that change. :| (Anyway, I think the change is good. I'm only perplex not finding the justification.) > This is the test I suggested: a check that mktime() returns -1, I think that test suggested by POSIX is bogus (redundant). If mktime(3) has failed, tm_wday is unchanged. If it has succeeded, tm_wday must be changed. Thus, the return value is meaningless for the purpose of determining if it has failed. > and since it can be a valid value, a second test on tm_wday > (where the input, which is ignored, has an invalid value such > as -1 here, or INT_MAX in your case; note that -1 may be more > efficient with some processors, and shorter to write). I didn't use -1 because I thought some weird weeks might contain 8 days (for some of those weird timezone adjustments), and that that might cause wday -1 to actually exist. Thus I chose INT_MIN, which is far far away from valid values, to represent an error. However, I assume that they were careful enough to make sure that such weeks do not exist, so yes, -1 will be better. (And if it's not, we'll blame Austin.) :) Cheers, Alex -- <https://www.alejandro-colomar.es/> [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v3] ctime.3: EXAMPLES: Add example program 2024-08-23 14:18 ` Alejandro Colomar @ 2024-08-23 15:26 ` Vincent Lefevre 2024-08-23 17:48 ` Alejandro Colomar 0 siblings, 1 reply; 25+ messages in thread From: Vincent Lefevre @ 2024-08-23 15:26 UTC (permalink / raw) To: Alejandro Colomar Cc: Xi Ruoyao, Paul Eggert, libc-alpha, DJ Delorie, linux-man, carlos, Robert C. Seacord, Jens Gustedt On 2024-08-23 16:18:21 +0200, Alejandro Colomar wrote: > Hi Vincent, > > On Fri, Aug 23, 2024 at 03:54:49PM GMT, Vincent Lefevre wrote: > > On 2024-08-23 15:12:16 +0200, Alejandro Colomar wrote: > > > Looking at the WG14 document logs, it seems it was added in n3147: > > > <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3147.txt> > > > > Thanks for the reference. Additional details can be found > > in CD2 ballot at > > > > https://open-std.org/JTC1/SC22/WG14/www/docs/n3148.doc > > It's interesting that WG14 claims that they're not aware of any existing > implementations that would modify tm_wday on failure. AFAIK, this is not a claim from WG14, but from the one who submitted the GB-159 comment. The claim is There is some existing practice where application code sets tm_wday to an out-of-range sentinel value and checks whether it was changed by mktime, and we are not aware of any implementation where this does not work. and this is rather vague: we do not know whether this existing practice is common and which implementations have been checked. > Although it's weird, because WG14 attributes that claim to the Austin > Group, and The comment attributes the issues to the Austin Group, but perhaps not all the details. > > which references the POSIX bug > > > > https://austingroupbugs.net/view.php?id=1614 > > I don't see any discussion about tm_wday in that Austin Group bug. :| > Maybe it happened in a mailing list or elsewhere. Yes, perhaps in the austin-group-l mailing-list. > (If any implementation does not conform, at least it should > be feasible to fix that implementation to conform.) That's something new in the future C23 standard. So I don't think that older implementations (stable releases) would change. > > This is the test I suggested: a check that mktime() returns -1, > > I think that test suggested by POSIX is bogus (redundant). If mktime(3) > has failed, tm_wday is unchanged. If it has succeeded, tm_wday must be > changed. Thus, the return value is meaningless for the purpose of > determining if it has failed. Yes, after some thoughts, I agree. However, it should be said that with pre-C23 implementations, it is not guaranteed to detect failures. Said otherwise, the change from if (mktime(&time_str) == -1) to if (time_str.tm_wday == -1) will avoid spurious failures (the case where -1 is a valid calendar value), but it might make some failures be undetected, though no implementations with such an issue are known. > > and since it can be a valid value, a second test on tm_wday > > (where the input, which is ignored, has an invalid value such > > as -1 here, or INT_MAX in your case; note that -1 may be more > > efficient with some processors, and shorter to write). > > I didn't use -1 because I thought some weird weeks might contain 8 days > (for some of those weird timezone adjustments), and that that might > cause wday -1 to actually exist. This is invalid and could cause crashes in programs, or worse. In C17: int tm_wday; // days since Sunday -- [0, 6] -- Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/> 100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/> Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon) ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v3] ctime.3: EXAMPLES: Add example program 2024-08-23 15:26 ` Vincent Lefevre @ 2024-08-23 17:48 ` Alejandro Colomar 2024-08-23 18:46 ` Robert Elz 2024-08-23 19:08 ` Paul Eggert 0 siblings, 2 replies; 25+ messages in thread From: Alejandro Colomar @ 2024-08-23 17:48 UTC (permalink / raw) To: Robert Elz, Andrew Josey, Geoff Clare, Vincent Lefevre Cc: Xi Ruoyao, Paul Eggert, libc-alpha, DJ Delorie, linux-man, carlos, Robert C. Seacord, Jens Gustedt, austin-group-l [-- Attachment #1: Type: text/plain, Size: 6547 bytes --] [CC += austin-group-l@opengroup.org] (Although I'm not sure if that mailing list is open. maybe it rejects mail from this account. Please anyone bounce it if you find that it doesn't reach the list.) [CC += Robert, Geoff, Andrew] Hi Vincent, Robert, Geoff, Andrew, On Fri, Aug 23, 2024 at 05:26:17PM GMT, Vincent Lefevre wrote: > On 2024-08-23 16:18:21 +0200, Alejandro Colomar wrote: > > Hi Vincent, > > > > On Fri, Aug 23, 2024 at 03:54:49PM GMT, Vincent Lefevre wrote: > > > On 2024-08-23 15:12:16 +0200, Alejandro Colomar wrote: > > > > Looking at the WG14 document logs, it seems it was added in n3147: > > > > <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3147.txt> > > > > > > Thanks for the reference. Additional details can be found > > > in CD2 ballot at > > > > > > https://open-std.org/JTC1/SC22/WG14/www/docs/n3148.doc > > > > It's interesting that WG14 claims that they're not aware of any existing > > implementations that would modify tm_wday on failure. > > AFAIK, this is not a claim from WG14, but from the one who submitted > the GB-159 comment. The claim is True. > There is some existing practice where application code sets tm_wday > to an out-of-range sentinel value and checks whether it was changed > by mktime, and we are not aware of any implementation where this > does not work. > > and this is rather vague: we do not know whether this existing practice > is common From what I can find with Debian's <https://codesearch.debian.net>, there's more than one. Still negligible compared to the amount of bogus checks comparing the return value with -1, but a decent number. I'm not sure we can call that common, though. boost python ceph And one project has the redundant code suggested by POSIX: pypy > and which implementations have been checked. Robert, Geoff, Andrew, can you please clarify? > > Although it's weird, because WG14 attributes that claim to the Austin > > Group, and > > The comment attributes the issues to the Austin Group, but perhaps > not all the details. > > > > which references the POSIX bug > > > > > > https://austingroupbugs.net/view.php?id=1614 > > > > I don't see any discussion about tm_wday in that Austin Group bug. :| > > Maybe it happened in a mailing list or elsewhere. > > Yes, perhaps in the austin-group-l mailing-list. Robert, Geoff, Andrew, can you please clarify where is the discussion that led to the following change?: On page 1331 line 44327 section mktime(), change: The mktime() function shall return the specified time since the Epoch encoded as a value of type time_t. If the time since the Epoch cannot be represented, the function shall return the value (time_t)-1 [CX]and set errno to indicate the error[/CX]. to: The mktime() function shall return the calculated time since the Epoch encoded as a value of type time_t. If the time since the Epoch cannot be represented as a time_t [CX]or the value to be returned in the tm_year member of the structure pointed to by timeptr cannot be represented as an int[/CX], the function shall return the value (time_t)-1 [CX]and set errno to [EOVERFLOW], and shall not change the value of the tm_wday component of the structure.[/CX] [CX]Since (time_t)-1 is a valid return value for a successful call to mktime(), an application wishing to check for error situations should set tm_wday to a value less than 0 or greater than 6 before calling mktime(). On return, if tm_wday has not changed an error has occurred.[/CX] We haven't found any mention at all in the Austin bug #1614, other than the change itself, which is weird. There must have been something elsewhere. (I do like the change, but I'd like to understand what research was done.) > > (If any implementation does not conform, at least it should > > be feasible to fix that implementation to conform.) > > That's something new in the future C23 standard. (And in POSIX.1-2024.) > So I don't think > that older implementations (stable releases) would change. You could argue with them that there's no way to test for errors other than this method, so if they don't fix their implementations, they are effectively broken. Or you may need to assume that under older standards, it was impossible to check for mktime(3) errors. Do not use implementations that conform to broken standards. :) > > > This is the test I suggested: a check that mktime() returns -1, > > > > I think that test suggested by POSIX is bogus (redundant). If mktime(3) > > has failed, tm_wday is unchanged. If it has succeeded, tm_wday must be > > changed. Thus, the return value is meaningless for the purpose of > > determining if it has failed. > > Yes, after some thoughts, I agree. > > However, it should be said that with pre-C23 implementations, > it is not guaranteed to detect failures. Under a pre-C23 (and pre-POSIX.1-2024) implementation, there was no method that would guarantee detecting failures. Or rather, there was no method that would be free of false positives. You could always test the return for -1, and reject some valid dates. Choose your poison. > Said otherwise, the change from > > if (mktime(&time_str) == -1) > > to > > if (time_str.tm_wday == -1) > > will avoid spurious failures (the case where -1 is a valid calendar > value), but it might make some failures be undetected, though no > implementations with such an issue are known. > > > > and since it can be a valid value, a second test on tm_wday > > > (where the input, which is ignored, has an invalid value such > > > as -1 here, or INT_MAX in your case; note that -1 may be more > > > efficient with some processors, and shorter to write). > > > > I didn't use -1 because I thought some weird weeks might contain 8 days > > (for some of those weird timezone adjustments), and that that might > > cause wday -1 to actually exist. > > This is invalid and could cause crashes in programs, or worse. > In C17: > > int tm_wday; // days since Sunday -- [0, 6] Hmmm, nice. I guess if a weekday was ever added, it would be given a name, and thus it would probably either repeat one of the sevenn, or be an eigth day, but not a -1th day. (Even if just because politicians don't think of negative week days.) So I guess it's safe to assume that tm_wday -1 will never exist. Good. Have a lovely day! Alex -- <https://www.alejandro-colomar.es/> [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v3] ctime.3: EXAMPLES: Add example program 2024-08-23 17:48 ` Alejandro Colomar @ 2024-08-23 18:46 ` Robert Elz 2024-08-23 19:08 ` Paul Eggert 1 sibling, 0 replies; 25+ messages in thread From: Robert Elz @ 2024-08-23 18:46 UTC (permalink / raw) To: Alejandro Colomar Cc: Andrew Josey, Geoff Clare, Vincent Lefevre, Xi Ruoyao, Paul Eggert, libc-alpha, DJ Delorie, linux-man, carlos, Jens Gustedt, austin-group-l Date: Fri, 23 Aug 2024 19:48:09 +0200 From: Alejandro Colomar <alx@kernel.org> Message-ID: <cb65drmcb6cotrz6rzkfuwg5aod2jta4ma6f6cds4pouk5tjdj@6wl6iwby2isi> I kind of suspect there has been some discussion I am not privy to preceding this, so if anything I add here seems redundant, or whatever, that's why. | (Although I'm not sure if that mailing list is open. maybe it rejects | mail from this account. Please anyone bounce it if you find that it | doesn't reach the list.) Same here. I am fairly sure (since I have received no recent messages) that I got dropped from the austin list during a period when munnari.oz.au was reachable only via IPv6 (something of an experiment, though the original reasoning was different). It appears that the austin-group mailing list is only able to transmit mail via IPv4. Shame. Also note that I removed "Robert C. Seacord" <rcseacord@gmail.com> from the recipient list, as gmail continue to refuse to receive mail from munnari - there was no point attempting that one. Someone can forward if that seems called for. | > and which implementations have been checked. | Robert, Geoff, Andrew, can you please clarify? Me, no, sorry, that is something from the linux world I think. I actually have no idea whether our implementation (Paul might be able to guess, since this is unlikely to have been changed from tzcode) whether our implementation alters tm_wday in various failure cases or not. | Robert, Geoff, Andrew, can you please clarify where is the discussion | that led to the following change?: There were a lot of discussions about mtime() - lots of it on the list, some of it in the mantis defect report database (associated with more than one bug), and more about strftime("%s") which is almost the same thing. Sorry, I can't point you at anything in particular which led to that. | You could argue with them that there's no way to test for errors other | than this method, That's probably a reasonable summary of the rationale. | I guess if a weekday was ever added, If there's anything about the management of times less likely to happen than that one, I cannot imagine it. Weeks with fewer days are possible, in bizarre circumstances (like when Gregorian time became standard) but not ones with more. It would be more likely that the concept of a week, and weekday names, would be eliminated, than a new day be added. Adding months would be a far more likely thing to happen - after all, that's happened before. Of course, if the whole way of measuring time were to be changed, then almost anything might appear as a replacement. mktime() wouldn't apply. kre ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v3] ctime.3: EXAMPLES: Add example program 2024-08-23 17:48 ` Alejandro Colomar 2024-08-23 18:46 ` Robert Elz @ 2024-08-23 19:08 ` Paul Eggert 2024-08-23 20:09 ` Hans Åberg 2024-08-23 20:34 ` Alejandro Colomar 1 sibling, 2 replies; 25+ messages in thread From: Paul Eggert @ 2024-08-23 19:08 UTC (permalink / raw) To: Alejandro Colomar, Robert Elz, Andrew Josey, Geoff Clare, Vincent Lefevre Cc: Xi Ruoyao, libc-alpha, DJ Delorie, linux-man, carlos, Robert C. Seacord, Jens Gustedt, austin-group-l On 2024-08-23 10:48, Alejandro Colomar wrote: > Robert, Geoff, Andrew, can you please clarify where is the discussion > that led to the following change?: Why does it matter? The tm_wday idea has worked everywhere for decades and is now standardized. For what it's worth, GNU Emacs has been using the tm_wday idea since 2018, when I made the following change: https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=b4eb908f858284a7962851fd99c94598f76afa6f and many GNU tools also use the idea, because I made a similar change to Gnulib too: https://git.savannah.gnu.org/cgit/gnulib.git/commit/?id=6ccfbb4ce5d4fa79f7afb48f3648f2e0401523c3 ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v3] ctime.3: EXAMPLES: Add example program 2024-08-23 19:08 ` Paul Eggert @ 2024-08-23 20:09 ` Hans Åberg 2024-08-23 20:34 ` Alejandro Colomar 1 sibling, 0 replies; 25+ messages in thread From: Hans Åberg @ 2024-08-23 20:09 UTC (permalink / raw) To: Paul Eggert Cc: Alejandro Colomar, Robert Elz, Andrew Josey, Geoff Clare, Vincent Lefevre, Xi Ruoyao, libc-alpha, DJ Delorie, linux-man, carlos, Robert C. Seacord, Jens Gustedt, austin-group-l > On 23 Aug 2024, at 21:08, Paul Eggert via austin-group-l at The Open Group <austin-group-l@opengroup.org> wrote: > > On 2024-08-23 10:48, Alejandro Colomar wrote: >> Robert, Geoff, Andrew, can you please clarify where is the discussion >> that led to the following change?: > > Why does it matter? The tm_wday idea has worked everywhere for decades and is now standardized. > > For what it's worth, GNU Emacs has been using the tm_wday idea since 2018, when I made the following change: I am a bit curious about the original discussion, which I cannot see: I have recently brushed up a C++ program I wrote that uses the Julian Day Number (JDN) and Julian date, which is used in astronomy. So, for example, 0 JDN, the Julian calendar date -4712-01-01, is a Monday, making it easy to find the day of the week, computing modulo 7. The Julian date 0.0 is noon UT on 0 JDN. https://en.wikipedia.org/wiki/Julian_day ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v3] ctime.3: EXAMPLES: Add example program 2024-08-23 19:08 ` Paul Eggert 2024-08-23 20:09 ` Hans Åberg @ 2024-08-23 20:34 ` Alejandro Colomar 1 sibling, 0 replies; 25+ messages in thread From: Alejandro Colomar @ 2024-08-23 20:34 UTC (permalink / raw) To: Paul Eggert Cc: Robert Elz, Andrew Josey, Geoff Clare, Vincent Lefevre, Xi Ruoyao, libc-alpha, DJ Delorie, linux-man, carlos, Robert C. Seacord, Jens Gustedt, austin-group-l [-- Attachment #1: Type: text/plain, Size: 898 bytes --] Hi Paul, On Fri, Aug 23, 2024 at 12:08:36PM GMT, Paul Eggert wrote: > On 2024-08-23 10:48, Alejandro Colomar wrote: > > Robert, Geoff, Andrew, can you please clarify where is the discussion > > that led to the following change?: > > Why does it matter? The tm_wday idea has worked everywhere for decades and > is now standardized. > > For what it's worth, GNU Emacs has been using the tm_wday idea since 2018, > when I made the following change: > > https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=b4eb908f858284a7962851fd99c94598f76afa6f > > and many GNU tools also use the idea, because I made a similar change to > Gnulib too: > > https://git.savannah.gnu.org/cgit/gnulib.git/commit/?id=6ccfbb4ce5d4fa79f7afb48f3648f2e0401523c3 Great! That gives me more confidence. Thanks a lot. :) Have a lovely night! Alex -- <https://www.alejandro-colomar.es/> [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v3] ctime.3: EXAMPLES: Add example program 2024-08-23 13:12 ` Alejandro Colomar 2024-08-23 13:54 ` Vincent Lefevre @ 2024-08-23 14:04 ` Brian Inglis 2024-08-23 14:25 ` Alejandro Colomar 1 sibling, 1 reply; 25+ messages in thread From: Brian Inglis @ 2024-08-23 14:04 UTC (permalink / raw) To: linux-man Cc: carlos, dj, eggert, jens.gustedt, libc-alpha, rcseacord, vincent, xry111, alx AFAICS from 9899 1998 Draft to 2023, the *mktime* wording has been essentially: "The original values of the tm_wday and tm_yday components of the structure are ignored, and the original values of the other components are not restricted to the ranges indicated above. On successful completion, the values of the tm_wday and tm_yday components of the structure are set appropriately," so the recommendation has been to do something like (pointless example): time_t tt = time(&tt); struct tm *tm = localtime(&tt); tm->tm_wday = tm->tm_yday = -1; if ((tt = mktime(tm)) == -1 && tm->tm_wday == -1 && tm->tm_yday == -1) error(...); -- Take care. Thanks, Brian Inglis Calgary, Alberta, Canada La perfection est atteinte Perfection is achieved non pas lorsqu'il n'y a plus rien à ajouter not when there is no more to add mais lorsqu'il n'y a plus rien à retirer but when there is no more to cut -- Antoine de Saint-Exupéry ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v3] ctime.3: EXAMPLES: Add example program 2024-08-23 14:04 ` Brian Inglis @ 2024-08-23 14:25 ` Alejandro Colomar 2024-08-23 18:31 ` Brian Inglis 0 siblings, 1 reply; 25+ messages in thread From: Alejandro Colomar @ 2024-08-23 14:25 UTC (permalink / raw) To: linux-man Cc: carlos, dj, eggert, jens.gustedt, libc-alpha, rcseacord, vincent, xry111 [-- Attachment #1: Type: text/plain, Size: 1604 bytes --] Hi Brian, On Fri, Aug 23, 2024 at 08:04:20AM GMT, Brian Inglis wrote: > AFAICS from 9899 1998 Draft to 2023, the *mktime* wording has been essentially: I find the above confusing. What is 9899 1998? The draft is for ISO/IEC 9899:2024. There's no 1998 in the name. > > "The original values of the tm_wday and tm_yday components of the structure > are ignored, and the original values of the other components are not > restricted to the ranges indicated above. On successful completion, the > values of the tm_wday and tm_yday components of the structure are set > appropriately," The text you've quoted is there since ISO C89. <https://port70.net/~nsz/c/c89/c89-draft.html#4.12.2.3> And that is not guarantee enough. It says that wday and yday are ignored (for the purposes of determining the return value). And it says that on success it modifies them. But that text is silent about what happens on error. It is C23 in 7.19.2.3p3 which provides a novel guarantee, that those fields won't be modified on a failed call. > > so the recommendation has been to do something like (pointless example): > > time_t tt = time(&tt); > struct tm *tm = localtime(&tt); > tm->tm_wday = tm->tm_yday = -1; > if ((tt = mktime(tm)) == -1 && tm->tm_wday == -1 && tm->tm_yday == -1) This conditional, just like the one in the POSIX 2024 standard, is redundant. Reading tm_wday is enough for determining a failure. Otherwise, what would you expect if tm_yday is 4 but tm_wday is -1? Half an error? :) Cheers, Alex -- <https://www.alejandro-colomar.es/> [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v3] ctime.3: EXAMPLES: Add example program 2024-08-23 14:25 ` Alejandro Colomar @ 2024-08-23 18:31 ` Brian Inglis 2024-08-23 20:27 ` Alejandro Colomar 0 siblings, 1 reply; 25+ messages in thread From: Brian Inglis @ 2024-08-23 18:31 UTC (permalink / raw) To: linux-man Cc: Alejandro Colomar, carlos, dj, eggert, jens.gustedt, libc-alpha, rcseacord, vincent, xry111 On 2024-08-23 08:25, Alejandro Colomar wrote: > Hi Brian, > > On Fri, Aug 23, 2024 at 08:04:20AM GMT, Brian Inglis wrote: >> AFAICS from 9899 1998 Draft to 2023, the *mktime* wording has been essentially: > > I find the above confusing. What is 9899 1998? The draft is for > ISO/IEC 9899:2024. There's no 1998 in the name. Sorry for the typo - from the original *1988* Draft from ANSI X3J11 88-090 1988-05-13 of ANSI/ISO/IEC 9899:1990 through 2023. >> "The original values of the tm_wday and tm_yday components of the structure >> are ignored, and the original values of the other components are not >> restricted to the ranges indicated above. On successful completion, the >> values of the tm_wday and tm_yday components of the structure are set >> appropriately," > > The text you've quoted is there since ISO C89. > <https://port70.net/~nsz/c/c89/c89-draft.html#4.12.2.3> > > And that is not guarantee enough. It says that wday and yday are > ignored (for the purposes of determining the return value). And it says > that on success it modifies them. But that text is silent about what > happens on error. It states they are set on successful completion, and implied left alone if not. > It is C23 in 7.19.2.3p3 which provides a novel guarantee, that those ^^^^^^^^^^ 7.29.2.3.p3 See "WD" https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3220.pdf#page=415 > fields won't be modified on a failed call. > >> >> so the recommendation has been to do something like (pointless example): >> >> time_t tt = time(&tt); >> struct tm *tm = localtime(&tt); >> tm->tm_wday = tm->tm_yday = -1; >> if ((tt = mktime(tm)) == -1 && tm->tm_wday == -1 && tm->tm_yday == -1) > > This conditional, just like the one in the POSIX 2024 standard, is > redundant. Reading tm_wday is enough for determining a failure. > > Otherwise, what would you expect if tm_yday is 4 but tm_wday is -1? Half an error? :) Checking both are still untouched guarantees an error! If one is set, it's a QoI bug, not an error ;^> -- Take care. Thanks, Brian Inglis Calgary, Alberta, Canada La perfection est atteinte Perfection is achieved non pas lorsqu'il n'y a plus rien à ajouter not when there is no more to add mais lorsqu'il n'y a plus rien à retirer but when there is no more to cut -- Antoine de Saint-Exupéry ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v3] ctime.3: EXAMPLES: Add example program 2024-08-23 18:31 ` Brian Inglis @ 2024-08-23 20:27 ` Alejandro Colomar 0 siblings, 0 replies; 25+ messages in thread From: Alejandro Colomar @ 2024-08-23 20:27 UTC (permalink / raw) To: linux-man Cc: carlos, dj, eggert, jens.gustedt, libc-alpha, rcseacord, vincent, xry111 [-- Attachment #1: Type: text/plain, Size: 2499 bytes --] Hi Brian, On Fri, Aug 23, 2024 at 12:31:01PM GMT, Brian Inglis wrote: > On 2024-08-23 08:25, Alejandro Colomar wrote: > > Hi Brian, > > > > On Fri, Aug 23, 2024 at 08:04:20AM GMT, Brian Inglis wrote: > > > AFAICS from 9899 1998 Draft to 2023, the *mktime* wording has been essentially: > > > > I find the above confusing. What is 9899 1998? The draft is for > > ISO/IEC 9899:2024. There's no 1998 in the name. > > Sorry for the typo - from the original *1988* Draft from ANSI X3J11 88-090 > 1988-05-13 of ANSI/ISO/IEC 9899:1990 through 2023. Ahh, thanks! > > > > "The original values of the tm_wday and tm_yday components of the structure > > > are ignored, and the original values of the other components are not > > > restricted to the ranges indicated above. On successful completion, the > > > values of the tm_wday and tm_yday components of the structure are set > > > appropriately," > > > > The text you've quoted is there since ISO C89. > > <https://port70.net/~nsz/c/c89/c89-draft.html#4.12.2.3> > > > > And that is not guarantee enough. It says that wday and yday are > > ignored (for the purposes of determining the return value). And it says > > that on success it modifies them. But that text is silent about what > > happens on error. > > It states they are set on successful completion, and implied left alone if not. ISO C leaves everything not explicitly stated as Undefined Behavior. :) Implied left alone is too optimistic. > > > It is C23 in 7.19.2.3p3 which provides a novel guarantee, that those > ^^^^^^^^^^ > 7.29.2.3.p3 Oops typo. :) > > See "WD" https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3220.pdf#page=415 > > > fields won't be modified on a failed call. > > > > > > > > so the recommendation has been to do something like (pointless example): > > > > > > time_t tt = time(&tt); > > > struct tm *tm = localtime(&tt); > > > tm->tm_wday = tm->tm_yday = -1; > > > if ((tt = mktime(tm)) == -1 && tm->tm_wday == -1 && tm->tm_yday == -1) > > > > This conditional, just like the one in the POSIX 2024 standard, is > > redundant. Reading tm_wday is enough for determining a failure. > > > > Otherwise, what would you expect if tm_yday is 4 but tm_wday is -1? Half an error? :) > > Checking both are still untouched guarantees an error! > If one is set, it's a QoI bug, not an error ;^> Cheers, Alex -- <https://www.alejandro-colomar.es/> [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v5] ctime.3: Document how to detect invalid or ambiguous times [not found] ` <xned6jlywd.fsf@greed.delorie.com> 2024-08-22 23:49 ` [PATCH v3] ctime.3: EXAMPLES: Add example program Alejandro Colomar @ 2024-08-24 8:46 ` Alejandro Colomar 2024-08-25 18:33 ` Alejandro Colomar 2024-08-30 11:09 ` [PATCH v6] ctime.3: EXAMPLES: " Alejandro Colomar 1 sibling, 2 replies; 25+ messages in thread From: Alejandro Colomar @ 2024-08-24 8:46 UTC (permalink / raw) To: Alejandro Colomar; +Cc: linux-man, DJ Delorie, Carlos O'Donell, Paul Eggert [-- Attachment #1: Type: text/plain, Size: 9281 bytes --] This example documents the corner cases of mktime(3), such as what happens during DST transitions, and other jumps in the calendar. Link: <https://www.redhat.com/en/blog/brief-history-mktime> Reported-by: DJ Delorie <dj@redhat.com> Cc: Carlos O'Donell <carlos@redhat.com> Cc: Paul Eggert <eggert@cs.ucla.edu> Signed-off-by: Alejandro Colomar <alx@kernel.org> --- Hi DJ, Paul, This is just a resend of v4. Forget v4. I forgot to send it in reply to the previous versions, and forgot to paste the rendered output. Here's how this looks: CAVEATS ... mktime() ... Passing an invalid time to mktime() or an invalid tm‐>tm_isdst value yields an unspecified result. Also, passing the value -1 in tm‐>tm_isdst will result in an ambiguous time during some DST transitions, which will also yield an unspecified result. See the example program in EXAMPLES. EXAMPLES The program below defines a wrapper that allows detecting invalid and ambiguous times, with EINVAL and ENOTUNIQ, respectively. The following shell session shows sample runs of the program: $ TZ=UTC ./a.out 1969 12 31 23 59 59 0; -1 $ $ export TZ=Europe/Madrid; $ $ ./a.out 2147483647 2147483647 00 00 00 00 ‐1; a.out: mktime: Value too large for defined data type $ $ ./a.out 2024 08 23 00 17 53 -1; 1724365073 $ ./a.out 2024 08 23 00 17 53 0; a.out: mktime: Invalid argument 1724368673 $ ./a.out 2024 08 23 00 17 53 1; 1724365073 $ $ ./a.out 2024 02 23 00 17 53 -1; 1708643873 $ ./a.out 2024 02 23 00 17 53 0; 1708643873 $ ./a.out 2024 02 23 00 17 53 1; a.out: mktime: Invalid argument 1708640273 $ $ ./a.out 2023 03 26 02 17 53 -1; a.out: mktime: Invalid argument 1679793473 $ $ ./a.out 2023 10 29 02 17 53 -1; a.out: mktime: Name not unique on network 1698542273 $ ./a.out 2023 10 29 02 17 53 0; 1698542273 $ ./a.out 2023 10 29 02 17 53 1; 1698538673 $ $ ./a.out 2023 02 29 12 00 00 -1; a.out: mktime: Invalid argument 1677668400 Program source: mktime.c #include <err.h> #include <errno.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #define is_signed(T) ((T) -1 < 1) time_t my_mktime(struct tm *tp); 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\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++); errno = 0; tm.tm_wday = -1; t = my_mktime(&tm); if (tm.tm_wday == -1) err(EXIT_FAILURE, "mktime"); if (errno == EINVAL || errno == ENOTUNIQ) warn("mktime"); if (is_signed(time_t)) printf("%jd\n", (intmax_t) t); else printf("%ju\n", (uintmax_t) t); exit(EXIT_SUCCESS); } time_t my_mktime(struct tm *tp) { int e, isdst; time_t t; struct tm tm; unsigned char wday[sizeof(tp->tm_wday)]; e = errno; tm = *tp; isdst = tp->tm_isdst; memcpy(wday, &tp->tm_wday, sizeof(wday)); tp->tm_wday = -1; t = mktime(tp); if (tp->tm_wday == -1) { memcpy(&tp->tm_wday, wday, sizeof(wday)); return -1; } if (isdst == -1) tm.tm_isdst = tp->tm_isdst; if ( tm.tm_sec != tp->tm_sec || tm.tm_min != tp->tm_min || tm.tm_hour != tp->tm_hour || tm.tm_mday != tp->tm_mday || tm.tm_mon != tp->tm_mon || tm.tm_year != tp->tm_year || tm.tm_isdst != tp->tm_isdst) { errno = EINVAL; return t; } if (isdst != -1) goto out; tm = *tp; tm.tm_isdst = !tm.tm_isdst; tm.tm_wday = -1; mktime(&tm); if (tm.tm_wday == -1) goto out; if (tm.tm_isdst != tp->tm_isdst) { errno = ENOTUNIQ; return t; } out: errno = e; return t; } Cheers, Alex Range-diff against v3: 1: e9e31a505 < -: --------- ctime.3: EXAMPLES: Add example program -: --------- > 1: b7ed55965 ctime.3: Document how to detect invalid or ambiguous times man/man3/ctime.3 | 93 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/man/man3/ctime.3 b/man/man3/ctime.3 index 0ad2b530f..934da149e 100644 --- a/man/man3/ctime.3 +++ b/man/man3/ctime.3 @@ -427,7 +427,30 @@ .SS mktime() .I tm->tm_wday field. See the example program in EXAMPLES. +.P +Passing an invalid time to +.BR mktime () +or an invalid +.I tm->tm_isdst +value +yields an unspecified result. +Also, +passing the value +.I \-1 +in +.I tm->tm_isdst +will result in an ambiguous time during some DST transitions, +which will also yield an unspecified result. +See the example program in EXAMPLES. .SH EXAMPLES +The program below defines a wrapper that +allows detecting invalid and ambiguous times, +with +.B EINVAL +and +.BR ENOTUNIQ , +respectively. +.P The following shell session shows sample runs of the program: .P .in +4n @@ -443,6 +466,7 @@ .SH EXAMPLES .RB $\~ "./a.out 2024 08 23 00 17 53 \-1" ; 1724365073 .RB $\~ "./a.out 2024 08 23 00 17 53 0" ; +a.out: mktime: Invalid argument 1724368673 .RB $\~ "./a.out 2024 08 23 00 17 53 1" ; 1724365073 @@ -452,12 +476,15 @@ .SH EXAMPLES .RB $\~ "./a.out 2024 02 23 00 17 53 0" ; 1708643873 .RB $\~ "./a.out 2024 02 23 00 17 53 1" ; +a.out: mktime: Invalid argument 1708640273 $ .RB $\~ "./a.out 2023 03 26 02 17 53 \-1" ; +a.out: mktime: Invalid argument 1679793473 $ .RB $\~ "./a.out 2023 10 29 02 17 53 \-1" ; +a.out: mktime: Name not unique on network 1698542273 .RB $\~ "./a.out 2023 10 29 02 17 53 0" ; 1698542273 @@ -465,6 +492,7 @@ .SH EXAMPLES 1698538673 $ .RB $\~ "./a.out 2023 02 29 12 00 00 \-1" ; +a.out: mktime: Invalid argument 1677668400 .EE .SS Program source: mktime.c @@ -472,13 +500,17 @@ .SS Program source: mktime.c .\" SRC BEGIN (mktime.c) .EX #include <err.h> +#include <errno.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <time.h> \& #define is_signed(T) ((T) \-1 < 1) \& +time_t my_mktime(struct tm *tp); +\& int main(int argc, char *argv[]) { @@ -500,10 +532,13 @@ .SS Program source: mktime.c tm.tm_sec = atoi(*p++); tm.tm_isdst = atoi(*p++); \& + errno = 0; tm.tm_wday = \-1; - t = mktime(&tm); + t = my_mktime(&tm); if (tm.tm_wday == \-1) err(EXIT_FAILURE, "mktime"); + if (errno == EINVAL || errno == ENOTUNIQ) + warn("mktime"); \& if (is_signed(time_t)) printf("%jd\[rs]n", (intmax_t) t); @@ -512,6 +547,62 @@ .SS Program source: mktime.c \& exit(EXIT_SUCCESS); } +\& +time_t +my_mktime(struct tm *tp) +{ + int e, isdst; + time_t t; + struct tm tm; + unsigned char wday[sizeof(tp\->tm_wday)]; +\& + e = errno; +\& + tm = *tp; + isdst = tp\->tm_isdst; +\& + memcpy(wday, &tp\->tm_wday, sizeof(wday)); + tp\->tm_wday = \-1; + t = mktime(tp); + if (tp\->tm_wday == \-1) { + memcpy(&tp\->tm_wday, wday, sizeof(wday)); + return \-1; + } +\& + if (isdst == \-1) + tm.tm_isdst = tp\->tm_isdst; +\& + if ( tm.tm_sec != tp\->tm_sec + || tm.tm_min != tp\->tm_min + || tm.tm_hour != tp\->tm_hour + || tm.tm_mday != tp\->tm_mday + || tm.tm_mon != tp\->tm_mon + || tm.tm_year != tp\->tm_year + || tm.tm_isdst != tp\->tm_isdst) + { + errno = EINVAL; + return t; + } +\& + if (isdst != \-1) + goto out; +\& + tm = *tp; + tm.tm_isdst = !tm.tm_isdst; +\& + tm.tm_wday = \-1; + mktime(&tm); + if (tm.tm_wday == \-1) + goto out; +\& + if (tm.tm_isdst != tp\->tm_isdst) { + errno = ENOTUNIQ; + return t; + } +out: + errno = e; + return t; +} .EE .\" SRC END .SH SEE ALSO base-commit: 6a7f1461b0e5474d50ef1920558dec103c0c058f -- 2.45.2 [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH v5] ctime.3: Document how to detect invalid or ambiguous times 2024-08-24 8:46 ` [PATCH v5] ctime.3: Document how to detect invalid or ambiguous times Alejandro Colomar @ 2024-08-25 18:33 ` Alejandro Colomar 2024-08-30 11:09 ` [PATCH v6] ctime.3: EXAMPLES: " Alejandro Colomar 1 sibling, 0 replies; 25+ messages in thread From: Alejandro Colomar @ 2024-08-25 18:33 UTC (permalink / raw) To: Paul Eggert; +Cc: linux-man, DJ Delorie, Carlos O'Donell [-- Attachment #1: Type: text/plain, Size: 10547 bytes --] Hi Paul, On Sat, Aug 24, 2024 at 10:46:20AM GMT, Alejandro Colomar wrote: > This example documents the corner cases of mktime(3), such as what > happens during DST transitions, and other jumps in the calendar. > > Link: <https://www.redhat.com/en/blog/brief-history-mktime> > Reported-by: DJ Delorie <dj@redhat.com> > Cc: Carlos O'Donell <carlos@redhat.com> > Cc: Paul Eggert <eggert@cs.ucla.edu> > Signed-off-by: Alejandro Colomar <alx@kernel.org> > --- Should I wait for a review, or are you ok with this patch? > > Hi DJ, Paul, > > This is just a resend of v4. Forget v4. > > I forgot to send it in reply to the previous versions, and forgot to > paste the rendered output. > > Here's how this looks: > > CAVEATS > ... > > mktime() > ... > > Passing an invalid time to mktime() or an invalid tm‐>tm_isdst > value yields an unspecified result. Also, passing the value -1 in > tm‐>tm_isdst will result in an ambiguous time during some DST > transitions, which will also yield an unspecified result. See the > example program in EXAMPLES. I think the wording is more or less what you suggested, leaving it as unspecified in those corner cases. Only in the example I show more details, for those who need to know what to do in those cases. > > EXAMPLES > The program below defines a wrapper that allows detecting invalid > and ambiguous times, with EINVAL and ENOTUNIQ, respectively. > > The following shell session shows sample runs of the program: > > $ TZ=UTC ./a.out 1969 12 31 23 59 59 0; > -1 > $ > $ export TZ=Europe/Madrid; > $ > $ ./a.out 2147483647 2147483647 00 00 00 00 ‐1; > a.out: mktime: Value too large for defined data type > $ > $ ./a.out 2024 08 23 00 17 53 -1; > 1724365073 > $ ./a.out 2024 08 23 00 17 53 0; > a.out: mktime: Invalid argument > 1724368673 > $ ./a.out 2024 08 23 00 17 53 1; > 1724365073 > $ > $ ./a.out 2024 02 23 00 17 53 -1; > 1708643873 > $ ./a.out 2024 02 23 00 17 53 0; > 1708643873 > $ ./a.out 2024 02 23 00 17 53 1; > a.out: mktime: Invalid argument > 1708640273 > $ > $ ./a.out 2023 03 26 02 17 53 -1; > a.out: mktime: Invalid argument > 1679793473 > $ > $ ./a.out 2023 10 29 02 17 53 -1; > a.out: mktime: Name not unique on network > 1698542273 > $ ./a.out 2023 10 29 02 17 53 0; > 1698542273 > $ ./a.out 2023 10 29 02 17 53 1; > 1698538673 > $ > $ ./a.out 2023 02 29 12 00 00 -1; > a.out: mktime: Invalid argument > 1677668400 > > Program source: mktime.c > > #include <err.h> > #include <errno.h> > #include <stdint.h> > #include <stdio.h> > #include <stdlib.h> > #include <string.h> > #include <time.h> > > #define is_signed(T) ((T) -1 < 1) > > time_t my_mktime(struct tm *tp); > > 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\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++); > > errno = 0; > tm.tm_wday = -1; > t = my_mktime(&tm); > if (tm.tm_wday == -1) > err(EXIT_FAILURE, "mktime"); > if (errno == EINVAL || errno == ENOTUNIQ) > warn("mktime"); > > if (is_signed(time_t)) > printf("%jd\n", (intmax_t) t); > else > printf("%ju\n", (uintmax_t) t); > > exit(EXIT_SUCCESS); > } > > time_t > my_mktime(struct tm *tp) > { > int e, isdst; > time_t t; > struct tm tm; > unsigned char wday[sizeof(tp->tm_wday)]; > > e = errno; > > tm = *tp; > isdst = tp->tm_isdst; > > memcpy(wday, &tp->tm_wday, sizeof(wday)); > tp->tm_wday = -1; > t = mktime(tp); > if (tp->tm_wday == -1) { > memcpy(&tp->tm_wday, wday, sizeof(wday)); > return -1; > } > > if (isdst == -1) > tm.tm_isdst = tp->tm_isdst; > > if ( tm.tm_sec != tp->tm_sec > || tm.tm_min != tp->tm_min > || tm.tm_hour != tp->tm_hour > || tm.tm_mday != tp->tm_mday > || tm.tm_mon != tp->tm_mon > || tm.tm_year != tp->tm_year > || tm.tm_isdst != tp->tm_isdst) > { > errno = EINVAL; > return t; > } > > if (isdst != -1) > goto out; > > tm = *tp; > tm.tm_isdst = !tm.tm_isdst; > > tm.tm_wday = -1; > mktime(&tm); > if (tm.tm_wday == -1) > goto out; > > if (tm.tm_isdst != tp->tm_isdst) { > errno = ENOTUNIQ; > return t; > } > out: > errno = e; > return t; > } > > Cheers, > Alex > > > Range-diff against v3: > 1: e9e31a505 < -: --------- ctime.3: EXAMPLES: Add example program > -: --------- > 1: b7ed55965 ctime.3: Document how to detect invalid or ambiguous times > > man/man3/ctime.3 | 93 +++++++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 92 insertions(+), 1 deletion(-) > > diff --git a/man/man3/ctime.3 b/man/man3/ctime.3 > index 0ad2b530f..934da149e 100644 > --- a/man/man3/ctime.3 > +++ b/man/man3/ctime.3 > @@ -427,7 +427,30 @@ .SS mktime() > .I tm->tm_wday > field. > See the example program in EXAMPLES. > +.P > +Passing an invalid time to > +.BR mktime () > +or an invalid > +.I tm->tm_isdst > +value > +yields an unspecified result. > +Also, > +passing the value > +.I \-1 > +in > +.I tm->tm_isdst > +will result in an ambiguous time during some DST transitions, > +which will also yield an unspecified result. > +See the example program in EXAMPLES. > .SH EXAMPLES > +The program below defines a wrapper that > +allows detecting invalid and ambiguous times, > +with > +.B EINVAL > +and > +.BR ENOTUNIQ , > +respectively. > +.P > The following shell session shows sample runs of the program: > .P > .in +4n > @@ -443,6 +466,7 @@ .SH EXAMPLES > .RB $\~ "./a.out 2024 08 23 00 17 53 \-1" ; > 1724365073 > .RB $\~ "./a.out 2024 08 23 00 17 53 0" ; > +a.out: mktime: Invalid argument > 1724368673 > .RB $\~ "./a.out 2024 08 23 00 17 53 1" ; > 1724365073 > @@ -452,12 +476,15 @@ .SH EXAMPLES > .RB $\~ "./a.out 2024 02 23 00 17 53 0" ; > 1708643873 > .RB $\~ "./a.out 2024 02 23 00 17 53 1" ; > +a.out: mktime: Invalid argument I'll change these error messages to say "my_mktime" instead of "mktime", since it's not a standard error. Have a lovely day! Alex > 1708640273 > $ > .RB $\~ "./a.out 2023 03 26 02 17 53 \-1" ; > +a.out: mktime: Invalid argument > 1679793473 > $ > .RB $\~ "./a.out 2023 10 29 02 17 53 \-1" ; > +a.out: mktime: Name not unique on network > 1698542273 > .RB $\~ "./a.out 2023 10 29 02 17 53 0" ; > 1698542273 > @@ -465,6 +492,7 @@ .SH EXAMPLES > 1698538673 > $ > .RB $\~ "./a.out 2023 02 29 12 00 00 \-1" ; > +a.out: mktime: Invalid argument > 1677668400 > .EE > .SS Program source: mktime.c > @@ -472,13 +500,17 @@ .SS Program source: mktime.c > .\" SRC BEGIN (mktime.c) > .EX > #include <err.h> > +#include <errno.h> > #include <stdint.h> > #include <stdio.h> > #include <stdlib.h> > +#include <string.h> > #include <time.h> > \& > #define is_signed(T) ((T) \-1 < 1) > \& > +time_t my_mktime(struct tm *tp); > +\& > int > main(int argc, char *argv[]) > { > @@ -500,10 +532,13 @@ .SS Program source: mktime.c > tm.tm_sec = atoi(*p++); > tm.tm_isdst = atoi(*p++); > \& > + errno = 0; > tm.tm_wday = \-1; > - t = mktime(&tm); > + t = my_mktime(&tm); > if (tm.tm_wday == \-1) > err(EXIT_FAILURE, "mktime"); > + if (errno == EINVAL || errno == ENOTUNIQ) > + warn("mktime"); > \& > if (is_signed(time_t)) > printf("%jd\[rs]n", (intmax_t) t); > @@ -512,6 +547,62 @@ .SS Program source: mktime.c > \& > exit(EXIT_SUCCESS); > } > +\& > +time_t > +my_mktime(struct tm *tp) > +{ > + int e, isdst; > + time_t t; > + struct tm tm; > + unsigned char wday[sizeof(tp\->tm_wday)]; > +\& > + e = errno; > +\& > + tm = *tp; > + isdst = tp\->tm_isdst; > +\& > + memcpy(wday, &tp\->tm_wday, sizeof(wday)); > + tp\->tm_wday = \-1; > + t = mktime(tp); > + if (tp\->tm_wday == \-1) { > + memcpy(&tp\->tm_wday, wday, sizeof(wday)); > + return \-1; > + } > +\& > + if (isdst == \-1) > + tm.tm_isdst = tp\->tm_isdst; > +\& > + if ( tm.tm_sec != tp\->tm_sec > + || tm.tm_min != tp\->tm_min > + || tm.tm_hour != tp\->tm_hour > + || tm.tm_mday != tp\->tm_mday > + || tm.tm_mon != tp\->tm_mon > + || tm.tm_year != tp\->tm_year > + || tm.tm_isdst != tp\->tm_isdst) > + { > + errno = EINVAL; > + return t; > + } > +\& > + if (isdst != \-1) > + goto out; > +\& > + tm = *tp; > + tm.tm_isdst = !tm.tm_isdst; > +\& > + tm.tm_wday = \-1; > + mktime(&tm); > + if (tm.tm_wday == \-1) > + goto out; > +\& > + if (tm.tm_isdst != tp\->tm_isdst) { > + errno = ENOTUNIQ; > + return t; > + } > +out: > + errno = e; > + return t; > +} > .EE > .\" SRC END > .SH SEE ALSO > > base-commit: 6a7f1461b0e5474d50ef1920558dec103c0c058f > -- > 2.45.2 > -- <https://www.alejandro-colomar.es/> [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v6] ctime.3: EXAMPLES: Document how to detect invalid or ambiguous times 2024-08-24 8:46 ` [PATCH v5] ctime.3: Document how to detect invalid or ambiguous times Alejandro Colomar 2024-08-25 18:33 ` Alejandro Colomar @ 2024-08-30 11:09 ` Alejandro Colomar 1 sibling, 0 replies; 25+ messages in thread From: Alejandro Colomar @ 2024-08-30 11:09 UTC (permalink / raw) To: Alejandro Colomar; +Cc: linux-man, DJ Delorie, Carlos O'Donell, Paul Eggert [-- Attachment #1: Type: text/plain, Size: 7600 bytes --] This example documents how to detect some corner cases of mktime(3), such as DST transitions and other jumps in the calendar. Link: <https://www.redhat.com/en/blog/brief-history-mktime> Cc: DJ Delorie <dj@redhat.com> Cc: Carlos O'Donell <carlos@redhat.com> Cc: Paul Eggert <eggert@cs.ucla.edu> Signed-off-by: Alejandro Colomar <alx@kernel.org> --- Hi DJ, Paul, v6: - Rebase after DJ's patch, which I've merged already. Now this one only adds code to EXAMPLES, since CAVEATS already documents the problems with invalid and ambiguous times. - Report these errors as my_mktime errors, no mktime ones. Below is a range-diff against v5. Have a lovely day! Alex Range-diff against v5: 1: b7ed55965 ! 1: 631714d92 ctime.3: Document how to detect invalid or ambiguous times @@ Metadata Author: Alejandro Colomar <alx@kernel.org> ## Commit message ## - ctime.3: Document how to detect invalid or ambiguous times + ctime.3: EXAMPLES: Document how to detect invalid or ambiguous times This example documents the corner cases of mktime(3), such as what happens during DST transitions, and other jumps in the calendar. Link: <https://www.redhat.com/en/blog/brief-history-mktime> - Reported-by: DJ Delorie <dj@redhat.com> + Cc: DJ Delorie <dj@redhat.com> Cc: Carlos O'Donell <carlos@redhat.com> Cc: Paul Eggert <eggert@cs.ucla.edu> Signed-off-by: Alejandro Colomar <alx@kernel.org> ## man/man3/ctime.3 ## @@ man/man3/ctime.3: .SS mktime() - .I tm->tm_wday - field. - See the example program in EXAMPLES. -+.P -+Passing an invalid time to -+.BR mktime () -+or an invalid -+.I tm->tm_isdst -+value -+yields an unspecified result. -+Also, -+passing the value -+.I \-1 -+in -+.I tm->tm_isdst -+will result in an ambiguous time during some DST transitions, -+which will also yield an unspecified result. -+See the example program in EXAMPLES. + may cause a clock time to be repeated or skipped + without a corresponding DST change. .SH EXAMPLES +The program below defines a wrapper that +allows detecting invalid and ambiguous times, @@ man/man3/ctime.3: .SH EXAMPLES .RB $\~ "./a.out 2024 08 23 00 17 53 \-1" ; 1724365073 .RB $\~ "./a.out 2024 08 23 00 17 53 0" ; -+a.out: mktime: Invalid argument ++a.out: my_mktime: Invalid argument 1724368673 .RB $\~ "./a.out 2024 08 23 00 17 53 1" ; 1724365073 @@ man/man3/ctime.3: .SH EXAMPLES .RB $\~ "./a.out 2024 02 23 00 17 53 0" ; 1708643873 .RB $\~ "./a.out 2024 02 23 00 17 53 1" ; -+a.out: mktime: Invalid argument ++a.out: my_mktime: Invalid argument 1708640273 $ .RB $\~ "./a.out 2023 03 26 02 17 53 \-1" ; -+a.out: mktime: Invalid argument ++a.out: my_mktime: Invalid argument 1679793473 $ .RB $\~ "./a.out 2023 10 29 02 17 53 \-1" ; -+a.out: mktime: Name not unique on network ++a.out: my_mktime: Name not unique on network 1698542273 .RB $\~ "./a.out 2023 10 29 02 17 53 0" ; 1698542273 @@ man/man3/ctime.3: .SH EXAMPLES 1698538673 $ .RB $\~ "./a.out 2023 02 29 12 00 00 \-1" ; -+a.out: mktime: Invalid argument ++a.out: my_mktime: Invalid argument 1677668400 .EE .SS Program source: mktime.c @@ man/man3/ctime.3: .SS Program source: mktime.c if (tm.tm_wday == \-1) err(EXIT_FAILURE, "mktime"); + if (errno == EINVAL || errno == ENOTUNIQ) -+ warn("mktime"); ++ warn("my_mktime"); \& if (is_signed(time_t)) printf("%jd\[rs]n", (intmax_t) t); man/man3/ctime.3 | 78 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/man/man3/ctime.3 b/man/man3/ctime.3 index 53abab6d9..acd6f1565 100644 --- a/man/man3/ctime.3 +++ b/man/man3/ctime.3 @@ -467,6 +467,14 @@ .SS mktime() may cause a clock time to be repeated or skipped without a corresponding DST change. .SH EXAMPLES +The program below defines a wrapper that +allows detecting invalid and ambiguous times, +with +.B EINVAL +and +.BR ENOTUNIQ , +respectively. +.P The following shell session shows sample runs of the program: .P .in +4n @@ -482,6 +490,7 @@ .SH EXAMPLES .RB $\~ "./a.out 2024 08 23 00 17 53 \-1" ; 1724365073 .RB $\~ "./a.out 2024 08 23 00 17 53 0" ; +a.out: my_mktime: Invalid argument 1724368673 .RB $\~ "./a.out 2024 08 23 00 17 53 1" ; 1724365073 @@ -491,12 +500,15 @@ .SH EXAMPLES .RB $\~ "./a.out 2024 02 23 00 17 53 0" ; 1708643873 .RB $\~ "./a.out 2024 02 23 00 17 53 1" ; +a.out: my_mktime: Invalid argument 1708640273 $ .RB $\~ "./a.out 2023 03 26 02 17 53 \-1" ; +a.out: my_mktime: Invalid argument 1679793473 $ .RB $\~ "./a.out 2023 10 29 02 17 53 \-1" ; +a.out: my_mktime: Name not unique on network 1698542273 .RB $\~ "./a.out 2023 10 29 02 17 53 0" ; 1698542273 @@ -504,6 +516,7 @@ .SH EXAMPLES 1698538673 $ .RB $\~ "./a.out 2023 02 29 12 00 00 \-1" ; +a.out: my_mktime: Invalid argument 1677668400 .EE .SS Program source: mktime.c @@ -511,13 +524,17 @@ .SS Program source: mktime.c .\" SRC BEGIN (mktime.c) .EX #include <err.h> +#include <errno.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <time.h> \& #define is_signed(T) ((T) \-1 < 1) \& +time_t my_mktime(struct tm *tp); +\& int main(int argc, char *argv[]) { @@ -539,10 +556,13 @@ .SS Program source: mktime.c tm.tm_sec = atoi(*p++); tm.tm_isdst = atoi(*p++); \& + errno = 0; tm.tm_wday = \-1; - t = mktime(&tm); + t = my_mktime(&tm); if (tm.tm_wday == \-1) err(EXIT_FAILURE, "mktime"); + if (errno == EINVAL || errno == ENOTUNIQ) + warn("my_mktime"); \& if (is_signed(time_t)) printf("%jd\[rs]n", (intmax_t) t); @@ -551,6 +571,62 @@ .SS Program source: mktime.c \& exit(EXIT_SUCCESS); } +\& +time_t +my_mktime(struct tm *tp) +{ + int e, isdst; + time_t t; + struct tm tm; + unsigned char wday[sizeof(tp\->tm_wday)]; +\& + e = errno; +\& + tm = *tp; + isdst = tp\->tm_isdst; +\& + memcpy(wday, &tp\->tm_wday, sizeof(wday)); + tp\->tm_wday = \-1; + t = mktime(tp); + if (tp\->tm_wday == \-1) { + memcpy(&tp\->tm_wday, wday, sizeof(wday)); + return \-1; + } +\& + if (isdst == \-1) + tm.tm_isdst = tp\->tm_isdst; +\& + if ( tm.tm_sec != tp\->tm_sec + || tm.tm_min != tp\->tm_min + || tm.tm_hour != tp\->tm_hour + || tm.tm_mday != tp\->tm_mday + || tm.tm_mon != tp\->tm_mon + || tm.tm_year != tp\->tm_year + || tm.tm_isdst != tp\->tm_isdst) + { + errno = EINVAL; + return t; + } +\& + if (isdst != \-1) + goto out; +\& + tm = *tp; + tm.tm_isdst = !tm.tm_isdst; +\& + tm.tm_wday = \-1; + mktime(&tm); + if (tm.tm_wday == \-1) + goto out; +\& + if (tm.tm_isdst != tp\->tm_isdst) { + errno = ENOTUNIQ; + return t; + } +out: + errno = e; + return t; +} .EE .\" SRC END .SH SEE ALSO -- 2.45.2 [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply related [flat|nested] 25+ messages in thread
end of thread, other threads:[~2024-08-30 11:09 UTC | newest]
Thread overview: 25+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-08-23 23:11 [PATCH v4] ctime.3: Document how to detect invalid or ambiguous times Alejandro Colomar
[not found] ` <xned6jlywd.fsf@greed.delorie.com>
2024-08-22 23:49 ` [PATCH v3] ctime.3: EXAMPLES: Add example program Alejandro Colomar
2024-08-23 4:57 ` Paul Eggert
2024-08-23 7:02 ` Alejandro Colomar
2024-08-23 7:26 ` Xi Ruoyao
2024-08-23 7:57 ` Vincent Lefevre
2024-08-23 12:28 ` Alejandro Colomar
2024-08-23 12:28 ` Xi Ruoyao
2024-08-23 12:53 ` Vincent Lefevre
2024-08-23 13:12 ` Alejandro Colomar
2024-08-23 13:54 ` Vincent Lefevre
2024-08-23 14:18 ` Alejandro Colomar
2024-08-23 15:26 ` Vincent Lefevre
2024-08-23 17:48 ` Alejandro Colomar
2024-08-23 18:46 ` Robert Elz
2024-08-23 19:08 ` Paul Eggert
2024-08-23 20:09 ` Hans Åberg
2024-08-23 20:34 ` Alejandro Colomar
2024-08-23 14:04 ` Brian Inglis
2024-08-23 14:25 ` Alejandro Colomar
2024-08-23 18:31 ` Brian Inglis
2024-08-23 20:27 ` Alejandro Colomar
2024-08-24 8:46 ` [PATCH v5] ctime.3: Document how to detect invalid or ambiguous times Alejandro Colomar
2024-08-25 18:33 ` Alejandro Colomar
2024-08-30 11:09 ` [PATCH v6] ctime.3: EXAMPLES: " Alejandro Colomar
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox