[20/59] Fix obscure bug when stdoffset == dstoffset

Message ID 20250105055750.1668721-21-eggert@cs.ucla.edu (mailing list archive)
State New
Headers
Series time: sync mktime from Gnulib |

Checks

Context Check Description
redhat-pt-bot/TryBot-apply_patch success Patch applied to master at the time it was sent

Commit Message

Paul Eggert Jan. 5, 2025, 5:56 a.m. UTC
  * 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(-)
  

Patch

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