bug-gnulib
[Top][All Lists]
Advanced

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

[PATCH 5/7] parse-datetime: don’t depend on tzname


From: Paul Eggert
Subject: [PATCH 5/7] parse-datetime: don’t depend on tzname
Date: Sun, 16 Jun 2024 16:45:29 -0700

* lib/parse-datetime.y (TIME_ZONE_BUFSIZE): Move earlier.
(parser_control) [!HAVE_STRUCT_TM_TM_ZONE]:
New member tz_abbr, to save abbrs calculated by strftime %Z.
(populate_local_time_zone_table): New function, which
optimizes the HAVE_STRUCT_TM_TM_ZONE case as before,
and falls back on strftime with %Z otherwise.
Although strftime %Z can be more accurate than the old tzname
based method, the new heuristic is still wrong so often that it
probably doesn’t help all that much.
(parse_datetime_body): Use it.
* modules/parse-datetime (Depends-on): Remove tzname.
---
 ChangeLog              |  13 +++++
 lib/parse-datetime.y   | 115 ++++++++++++++++++++++-------------------
 modules/parse-datetime |   3 +-
 3 files changed, 76 insertions(+), 55 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 5c24caebca..d956d9a046 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,18 @@
 2024-06-16  Paul Eggert  <eggert@cs.ucla.edu>
 
+       parse-datetime: don’t depend on tzname
+       * lib/parse-datetime.y (TIME_ZONE_BUFSIZE): Move earlier.
+       (parser_control) [!HAVE_STRUCT_TM_TM_ZONE]:
+       New member tz_abbr, to save abbrs calculated by strftime %Z.
+       (populate_local_time_zone_table): New function, which
+       optimizes the HAVE_STRUCT_TM_TM_ZONE case as before,
+       and falls back on strftime with %Z otherwise.
+       Although strftime %Z can be more accurate than the old tzname
+       based method, the new heuristic is still wrong so often that it
+       probably doesn’t help all that much.
+       (parse_datetime_body): Use it.
+       * modules/parse-datetime (Depends-on): Remove tzname.
+
        time_r: refactor tm_zone tests
        * m4/tm_gmtoff.m4 (gl_TM_GMTOFF): Also check for tm_zone
        and define HAVE_STRUCT_TM_TM_ZONE accordingly.
diff --git a/lib/parse-datetime.y b/lib/parse-datetime.y
index f98e7200d6..665401d422 100644
--- a/lib/parse-datetime.y
+++ b/lib/parse-datetime.y
@@ -144,6 +144,9 @@ typedef struct
 /* Meridian: am, pm, or 24-hour style.  */
 enum { MERam, MERpm, MER24 };
 
+/* Maximum length of a time zone abbreviation, plus 1.  */
+enum { TIME_ZONE_BUFSIZE = INT_STRLEN_BOUND (intmax_t) + sizeof ":MM:SS" };
+
 /* A reasonable upper bound for the buffer used in debug output.  */
 enum { DBGBUFSIZE = 100 };
 
@@ -230,6 +233,11 @@ typedef struct
 
   /* Table of local time zone abbreviations, terminated by a null entry.  */
   table local_time_zone_table[3];
+
+#if !HAVE_STRUCT_TM_TM_ZONE
+  /* The abbreviations in LOCAL_TIME_ZONE_TABLE.  */
+  char tz_abbr[2][TIME_ZONE_BUFSIZE];
+#endif
 } parser_control;
 
 static bool
@@ -386,8 +394,6 @@ str_days (parser_control *pc, char *buffer, int n)
 
 /* Convert a time zone to its string representation.  */
 
-enum { TIME_ZONE_BUFSIZE = INT_STRLEN_BOUND (intmax_t) + sizeof ":MM:SS" } ;
-
 static char const *
 time_zone_str (int time_zone, char time_zone_buf[TIME_ZONE_BUFSIZE])
 {
@@ -1565,6 +1571,33 @@ mktime_ok (struct tm const *tm0, struct tm const *tm1)
             | (tm0->tm_year ^ tm1->tm_year));
 }
 
+/* Populate PC's local time zone table with information from TM.  */
+
+static void
+populate_local_time_zone_table (parser_control *pc, struct tm const *tm)
+{
+  bool first_entry_exists = !!pc->local_time_zone_table[0].name;
+
+  /* The table entry to be filled in.  There are only two, so this is
+     the first entry if it is missing, the second entry otherwise.  */
+  table *e = &pc->local_time_zone_table[first_entry_exists];
+
+  e->type = tLOCAL_ZONE;
+  e->value = tm->tm_isdst;
+
+  char const *zone = NULL;
+#if HAVE_STRUCT_TM_TM_ZONE
+  if (tm->tm_zone[0])
+    zone = tm->tm_zone;
+#else
+  char *tz_abbr = pc->tz_abbr[first_entry_exists];
+  if (nstrftime (tz_abbr, TIME_ZONE_BUFSIZE, "%Z", tm, 0, 0))
+    zone = tz_abbr;
+#endif
+  e->name = zone;
+  e[1].name = NULL;
+}
+
 /* Debugging: format a 'struct tm' into a buffer, taking the parser's
    timezone information into account (if pc != NULL).  */
 static char const *
@@ -1833,61 +1866,37 @@ parse_datetime_body (struct timespec *result, char 
const *p,
   pc.debug_year_seen = false;
   pc.debug_ordinal_day_seen = false;
 
-#if HAVE_STRUCT_TM_TM_ZONE
-  pc.local_time_zone_table[0].name = tmp.tm_zone;
-  pc.local_time_zone_table[0].type = tLOCAL_ZONE;
-  pc.local_time_zone_table[0].value = tmp.tm_isdst;
-  pc.local_time_zone_table[1].name = NULL;
+  pc.local_time_zone_table[0].name = NULL;
+  populate_local_time_zone_table (&pc, &tmp);
 
   /* Probe the names used in the next three calendar quarters, looking
      for a tm_isdst different from the one we already have.  */
-  {
-    int quarter;
-    for (quarter = 1; quarter <= 3; quarter++)
-      {
-        time_t probe;
-        if (ckd_add (&probe, Start, quarter * (90 * 24 * 60 * 60)))
-          break;
-        struct tm probe_tm;
-        if (localtime_rz (tz, &probe, &probe_tm) && probe_tm.tm_zone
-            && probe_tm.tm_isdst != pc.local_time_zone_table[0].value)
-          {
-              {
-                pc.local_time_zone_table[1].name = probe_tm.tm_zone;
-                pc.local_time_zone_table[1].type = tLOCAL_ZONE;
-                pc.local_time_zone_table[1].value = probe_tm.tm_isdst;
-                pc.local_time_zone_table[2].name = NULL;
-              }
-            break;
-          }
-      }
-  }
-#else
-#if HAVE_TZNAME_ARRAY
-  {
-    int i;
-    for (i = 0; i < 2; i++)
-      {
-        pc.local_time_zone_table[i].name = tzname[i];
-        pc.local_time_zone_table[i].type = tLOCAL_ZONE;
-        pc.local_time_zone_table[i].value = i;
-      }
-    pc.local_time_zone_table[i].name = NULL;
-  }
-#else
-  pc.local_time_zone_table[0].name = NULL;
-#endif
-#endif
-
-  if (pc.local_time_zone_table[0].name && pc.local_time_zone_table[1].name
-      && ! strcmp (pc.local_time_zone_table[0].name,
-                   pc.local_time_zone_table[1].name))
+  for (int quarter = 1; quarter <= 3; quarter++)
     {
-      /* This locale uses the same abbreviation for standard and
-         daylight times.  So if we see that abbreviation, we don't
-         know whether it's daylight time.  */
-      pc.local_time_zone_table[0].value = -1;
-      pc.local_time_zone_table[1].name = NULL;
+      time_t probe;
+      if (ckd_add (&probe, Start, quarter * (90 * 24 * 60 * 60)))
+        break;
+      struct tm probe_tm;
+      if (localtime_rz (tz, &probe, &probe_tm)
+          && (! pc.local_time_zone_table[0].name
+              || probe_tm.tm_isdst != pc.local_time_zone_table[0].value))
+        {
+          populate_local_time_zone_table (&pc, &probe_tm);
+          if (pc.local_time_zone_table[1].name)
+            {
+              if (! strcmp (pc.local_time_zone_table[0].name,
+                            pc.local_time_zone_table[1].name))
+                {
+                  /* This locale uses the same abbreviation for standard and
+                     daylight times.  So if we see that abbreviation, we don't
+                     know whether it's daylight time.  */
+                  pc.local_time_zone_table[0].value = -1;
+                  pc.local_time_zone_table[1].name = NULL;
+                }
+
+              break;
+            }
+        }
     }
 
   if (yyparse (&pc) != 0)
diff --git a/modules/parse-datetime b/modules/parse-datetime
index 06c6f6173e..e8ac3e725d 100644
--- a/modules/parse-datetime
+++ b/modules/parse-datetime
@@ -5,8 +5,8 @@ Files:
 doc/parse-datetime.texi
 lib/parse-datetime.h
 lib/parse-datetime.y
-m4/tm_gmtoff.m4
 m4/parse-datetime.m4
+m4/tm_gmtoff.m4
 
 Depends-on:
 assert-h
@@ -28,7 +28,6 @@ time-h
 time_r
 time_rz
 timegm
-tzname
 
 configure.ac:
 gl_PARSE_DATETIME
-- 
2.43.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]