[PATCH v6] ctime.3: EXAMPLES: Document how to detect invalid or ambiguous times

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxx>
Cc: Carlos O'Donell <carlos@xxxxxxxxxx>
Cc: Paul Eggert <eggert@xxxxxxxxxxx>
Signed-off-by: Alejandro Colomar <alx@xxxxxxxxxx>
---

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@xxxxxxxxxx>
     
      ## 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@xxxxxxxxxx>
    +    Cc: DJ Delorie <dj@xxxxxxxxxx>
         Cc: Carlos O'Donell <carlos@xxxxxxxxxx>
         Cc: Paul Eggert <eggert@xxxxxxxxxxx>
         Signed-off-by: Alejandro Colomar <alx@xxxxxxxxxx>
     
      ## 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: signature.asc
Description: PGP signature


[Index of Archives]     [Kernel Documentation]     [Netdev]     [Linux Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux