[PATCH 20/59] Fix obscure bug when stdoffset == dstoffset
Paul Eggert
eggert@cs.ucla.edu
Sun Jan 5 05:56:55 GMT 2025
* time/tst-tzname.c (do_test): Test odd (but allowed by POSIX)
zone that has the same UTC offset in both standard time and DST.
* time/tzset.c (enum tz_rule_type): This type now has an enum tag.
(NO_DST): New value for the type.
(update_vars): Set __daylight depending the type, not on whether
offsets differ.
(parse_rule): Do not set rule type unless successful.
(tzset_internal): Default rules to NO_DST, not to J0.
(compute_change): Do not adjust if NO_DST.
---
time/tst-tzname.c | 25 +++++++++++++++++++++++++
time/tzset.c | 19 ++++++++++++-------
2 files changed, 37 insertions(+), 7 deletions(-)
diff --git a/time/tst-tzname.c b/time/tst-tzname.c
index 5009328e85..b9b4aea35e 100644
--- a/time/tst-tzname.c
+++ b/time/tst-tzname.c
@@ -43,6 +43,31 @@ do_test (void)
printf ("FAIL: TZ=%s, tzname[0] = %s\n", TZDEFRULES, tzname[0]);
result = 1;
}
+
+ static char const oddzone[] = "XST12XST12,M9.5.0,M4.1.0";
+ setenv ("TZ", oddzone, 1);
+ tzset ();
+ if (strcmp (tzname[0], "XST") != 0)
+ {
+ printf ("FAIL: TZ=%s, tzname[0] = %s\n", oddzone, tzname[0]);
+ result = 1;
+ }
+ if (strcmp (tzname[1], "XST") != 0)
+ {
+ printf ("FAIL: TZ=%s, tzname[1] = %s\n", oddzone, tzname[1]);
+ result = 1;
+ }
+ if (daylight <= 0)
+ {
+ printf ("FAIL: TZ=%s, daylight = %d\n", oddzone, daylight);
+ result = 1;
+ }
+ if (timezone != 12 * 60 * 60)
+ {
+ printf ("FAIL: TZ=%s, timezone = %ld\n", oddzone, timezone);
+ result = 1;
+ }
+
return result;
}
diff --git a/time/tzset.c b/time/tzset.c
index 8f7315dabe..e001a5898c 100644
--- a/time/tzset.c
+++ b/time/tzset.c
@@ -47,7 +47,7 @@ typedef struct
const char *name;
/* When to change. */
- enum { J0, J1, M } type; /* Interpretation of: */
+ enum tz_rule_type { NO_DST, J0, J1, M } type; /* Interpretation of: */
unsigned short int m, n, d; /* Month, week, day. */
int secs; /* Time of day. */
@@ -128,7 +128,7 @@ static char *old_tz;
static void
update_vars (void)
{
- __daylight = tz_rules[0].offset != tz_rules[1].offset;
+ __daylight = tz_rules[1].type != NO_DST;
__timezone = -tz_rules[0].offset;
__tzname[0] = (char *) tz_rules[0].name;
__tzname[1] = (char *) tz_rules[1].name;
@@ -267,6 +267,7 @@ parse_rule (const char **tzp, int whichrule)
{
const char *tz = *tzp;
tz_rule *tzr = &tz_rules[whichrule];
+ enum tz_rule_type type;
/* Ignore comma to support string following the incorrect
specification in early POSIX.1 printings. */
@@ -276,7 +277,7 @@ parse_rule (const char **tzp, int whichrule)
bool is_J = *tz == 'J';
if (is_J || isdigit (*tz))
{
- tzr->type = is_J ? J1 : J0;
+ type = is_J ? J1 : J0;
tz += is_J;
int d = parse_int (&tz);
if (! (is_J <= d && d <= 365))
@@ -285,7 +286,7 @@ parse_rule (const char **tzp, int whichrule)
}
else if (*tz == 'M')
{
- tzr->type = M;
+ type = M;
tz++;
int i = parse_int (&tz);
if (! (1 <= i && i <= 12 && *tz++ == '.'))
@@ -308,7 +309,7 @@ parse_rule (const char **tzp, int whichrule)
of 2005 [Pub. L. no. 109-58, 119 Stat 594 (2005)].
Below is the equivalent of "M3.2.0,M11.1.0" [/2 not needed
since 2:00AM is the default]. */
- tzr->type = M;
+ type = M;
if (tzr == &tz_rules[0])
{
tzr->m = 3;
@@ -341,6 +342,7 @@ parse_rule (const char **tzp, int whichrule)
secs = 2 * 60 * 60;
tzr->secs = secs;
+ tzr->type = type;
tzr->computed_for = LLONG_MIN;
*tzp = tz;
return true;
@@ -428,8 +430,8 @@ tzset_internal (int always)
{
memset (tz_rules, '\0', sizeof tz_rules);
tz_rules[0].name = tz_rules[1].name = "UTC";
- if (J0 != 0)
- tz_rules[0].type = tz_rules[1].type = J0;
+ if (NO_DST != 0)
+ tz_rules[0].type = tz_rules[1].type = NO_DST;
update_vars ();
return;
}
@@ -461,6 +463,9 @@ compute_change (tz_rule *rule, long long int year)
switch (rule->type)
{
+ case NO_DST:
+ break;
+
case J1:
/* Jn - Julian day, 1 == January 1, 60 == March 1 even in leap years.
In non-leap years, or if the day number is 59 or less, just
--
2.45.2
More information about the Libc-alpha
mailing list