It's typically faster to parse a TZif file's TZ spec once after TZ
changes instead of parsing it on every call to localtime, as most
slim TZif files' last transitions precede the current time.
* time/tzfile.c (rule_stdoff, daylight_saved):
Remove static vars. All uses removed.
(__tzfile_read): Parse the tzspec here. Simplify the guesswork
for tzname etc.: if a tzspec exists, use its proleptic values as
this is more likely to be what obsolescent code wants; otherwise,
simplify three loops into one.
(__tzfile_compute): Do not parse tzspec, as tzset now does that.
* time/tzset.c (tzset_internal): When TZ hasn't changed,
update external vars only if TZ is proleptic.
(tzset_internal): Do not attempt to migrate __tzfile_read's
settings of tzname etc. into tz_rules as that would mess
up later use by __tzfile_compute of a parsed tzspec.
---
time/tzfile.c | 99 ++++++++++++++++++++-------------------------------
time/tzset.c | 27 +++++---------
2 files changed, 47 insertions(+), 79 deletions(-)
@@ -64,15 +64,10 @@ static unsigned char *type_idxs;
static tzidx typecnt;
static struct ttinfo *types;
static char *zone_names;
-static long int rule_stdoff;
static tzidx leapcnt;
static struct leap *leaps;
static char *tzspec;
-/* Used to restore the daylight variable during time conversion, as if
- tzset had been called. */
-static int daylight_saved;
-
#include <endian.h>
#include <byteswap.h>
@@ -516,65 +511,53 @@ __tzfile_read (const char *file)
if (__tzstring (&zone_names[types[i].idx]) == NULL)
goto ret_free_transitions;
- /* Find the standard and daylight time offsets used by the rule file.
- We choose the offsets in the types of each flavor that are
- transitioned to earliest in time. */
- __tzname[0] = NULL;
- __tzname[1] = NULL;
- for (i = timecnt; i > 0; i--)
- {
- struct ttinfo *ttype = &types[type_idxs[i - 1]];
- unsigned char dst = ttype->dst;
-
- if (__tzname[dst] == NULL)
- {
- __tzname[dst] = __tzstring (&zone_names[ttype->idx]);
+ /* POSIX does not say what daylight, timezone and tzname should be;
+ try to set them to something reasonable. */
- if (__tzname[1 - dst] != NULL)
- break;
- }
- }
- if (__tzname[0] == NULL)
+ if (tzspec != NULL)
{
- /* This should only happen if there are no transition rules.
- In this case there's usually only one single type, unless
- e.g. the data file has a truncated time-range. */
- __tzname[0] = __tzstring (zone_names);
+ /* The usual case with tzspec; just use its values. */
+ if (__glibc_unlikely (! __tzset_parse_tz (tzspec)))
+ goto ret_free_transitions;
}
- if (__tzname[1] == NULL)
- __tzname[1] = __tzname[0];
-
- daylight_saved = 0;
- if (timecnt == 0)
- /* Use the first rule (which should also be the only one). */
- rule_stdoff = types[0].utoff;
else
{
- rule_stdoff = 0;
-
- /* Search for the last rule with a standard time offset. This
- will be used for the global timezone variable. */
- i = timecnt - 1;
- do
- if (!types[type_idxs[i]].dst)
- {
- rule_stdoff = types[type_idxs[i]].utoff;
+ /* The unusual case without tzspec; infer from transitions.
+ Default to the first type's offset and isdst. */
+ __timezone = -types[0].utoff;
+ __daylight = types[0].dst;
+
+ /* Find the abbr and offset for the last transition to standard time,
+ and the abbr for the last transition to DST. */
+ __tzname[0] = NULL;
+ __tzname[1] = NULL;
+ for (i = timecnt; i > 0; i--)
+ {
+ struct ttinfo *ttype = &types[type_idxs[i - 1]];
+ unsigned char dst = ttype->dst;
+
+ if (__tzname[dst] == NULL)
+ {
+ __tzname[dst] = __tzstring (&zone_names[ttype->idx]);
+ if (!dst)
+ __timezone = -ttype->utoff;
+ }
+
+ if (__tzname[1 - dst] != NULL)
break;
- }
- else
- daylight_saved = 1;
- while (i-- > 0);
-
- /* Keep searching to see if there is a DST rule. This
- information will be used to set the global daylight
- variable. */
- while (i-- > 0 && !daylight_saved)
- daylight_saved = types[type_idxs[i]].dst;
+ }
+ /* With no appropriate transitions, default standard time's
+ abbreviation to that of the first type, and default DST's
+ abbreviation to that of standard time. Also, set 'daylight'
+ if a DST transition was found. */
+ if (__tzname[0] == NULL)
+ __tzname[0] = __tzstring (&zone_names[types[0].idx]);
+ if (__tzname[1] == NULL)
+ __tzname[1] = __tzname[0];
+ else
+ __daylight = 1;
}
- __daylight = daylight_saved;
- __timezone = -rule_stdoff;
-
/* Remember the inode and device number and modification time. */
tzfile_dev = st.st_dev;
tzfile_ino = st.st_ino;
@@ -618,10 +601,6 @@ __tzfile_compute (__time64_t timer, int use_localtime,
goto found;
}
- /* Parse the proleptic TZ string. If this fails do not use it. */
- if (__glibc_unlikely (! __tzset_parse_tz (tzspec)))
- goto use_last;
-
/* Convert to broken down structure. If this fails do not
use the string. */
if (__glibc_unlikely (__offtime (timer, 0, 0, tp) == NULL))
@@ -412,15 +412,18 @@ tzset_internal (bool always)
tz = TZDEFAULT;
/* A leading colon means "implementation defined syntax".
- We ignore the colon and always use the same algorithm:
+ Ignore the colon and always use the same algorithm:
try a data file, and if none exists parse the 1003.1 syntax. */
if (*tz == ':')
++tz;
- /* If the value changed has not since the last run,
- simply update internal vars. */
+ /* If the value has not changed since the last run,
+ simply update external vars if POSIX requires it. */
if (old_tz != NULL && strcmp (tz, old_tz) == 0)
- update_vars ();
+ {
+ if (!use_tzfile)
+ update_vars ();
+ }
else
{
/* Save the value of 'tz'. */
@@ -429,21 +432,7 @@ tzset_internal (bool always)
/* Try to read a data file. */
use_tzfile = __tzfile_read (tz);
- if (use_tzfile)
- {
- /* Save equivalent of 'daylight' for later use by update_vars.
- Although the other external variables have unspecified values
- and so need not be saved in the usual case, save them anyway,
- as POSIX requires this for rare file-backed proleptic
- TZ strings like "EST5EDT", and it is more likely to match user
- expectations for geographical TZ strings. */
- enum tz_rule_type some_DST = J0; /* anything but NO_DST */
- tz_rules[1].type = NO_DST + __daylight * (some_DST - NO_DST);
- tz_rules[0].offset = -__timezone;
- tz_rules[0].name = __tzname[0];
- tz_rules[1].name = __tzname[1];
- }
- else
+ if (!use_tzfile)
{
/* No data file found. Default to UTC without leap seconds if
TZDEFAULT is broken. */