[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
- new module 'tzname', Bruno Haible, 2024/06/06
- Re: new module 'tzname', Paul Eggert, 2024/06/06
- Re: new module 'tzname', tm_zone and tm_gmtoff, Bruno Haible, 2024/06/06
- Re: new module 'tzname', tm_zone and tm_gmtoff, Paul Eggert, 2024/06/06
- Re: new module 'tzname', tm_zone and tm_gmtoff, Bruno Haible, 2024/06/06
- [PATCH 0/7] avoiding tzname usage in Gnulib code, Paul Eggert, 2024/06/16
- [PATCH] Fix typos in ChangeLog and getpagesize.texi, Paul Eggert, 2024/06/16
- [PATCH 2/7] time_r-tests: avoid tzname test, Paul Eggert, 2024/06/16
- [PATCH 1/7] nstrftime: rename HAVE_TM_GMTOFF, Paul Eggert, 2024/06/16
- [PATCH 5/7] parse-datetime: don’t depend on tzname,
Paul Eggert <=
- [PATCH 4/7] time_r: refactor tm_zone tests, Paul Eggert, 2024/06/16
- [PATCH 6/7] nstrftime, time_rz: don’t depend on tzname, Paul Eggert, 2024/06/16
- Re: [PATCH 6/7] nstrftime, time_rz: don’t depend on tzname, Bruno Haible, 2024/06/17
- Re: [PATCH 6/7] nstrftime, time_rz: don’t depend on tzname, Paul Eggert, 2024/06/17
- Re: [PATCH 6/7] nstrftime, time_rz: don’t depend on tzname, Bruno Haible, 2024/06/17
- Re: [PATCH 6/7] nstrftime, time_rz: don’t depend on tzname, Bruno Haible, 2024/06/17
- Re: [PATCH 6/7] nstrftime, time_rz: don’t depend on tzname, Bruno Haible, 2024/06/17
- Re: [PATCH 6/7] nstrftime, time_rz: don’t depend on tzname, Paul Eggert, 2024/06/17
- Re: [PATCH 6/7] nstrftime, -0000, Bruno Haible, 2024/06/18
- Re: [PATCH 6/7] nstrftime, -0000, Paul Eggert, 2024/06/18