mirror of
https://git.savannah.gnu.org/git/gnulib.git
synced 2025-08-08 17:22:05 +03:00
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.
This commit is contained in:
13
ChangeLog
13
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.
|
||||
|
@@ -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,54 +1866,25 @@ 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++)
|
||||
for (int 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)
|
||||
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)
|
||||
{
|
||||
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,
|
||||
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
|
||||
@@ -1890,6 +1894,11 @@ parse_datetime_body (struct timespec *result, char const *p,
|
||||
pc.local_time_zone_table[1].name = NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (yyparse (&pc) != 0)
|
||||
{
|
||||
if (debugging (&pc))
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user