[44/59] Handle TZif time type 0 correctly

Message ID 20250105055750.1668721-45-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:57 a.m. UTC
  * time/tzfile.c (__tzfile_compute): For time stamps before the
first transition, or for all transitions if no TZ string is
specified, use time type 0 as specified by Internet RFC 9636
section 3.2.  Omit an unnecessary loop to set tzname, daylight,
and timezone as that behavior is undocumented, POSIX does not
require it, and it does not make sense in general.  Instead, just
set tzname[isdst] as that is all that makes sense (particularly in
light of the time type 0 fix) and that might conceivably help
old-fashioned apps.
---
 time/tzfile.c | 88 ++++++++++-----------------------------------------
 1 file changed, 17 insertions(+), 71 deletions(-)
  

Patch

diff --git a/time/tzfile.c b/time/tzfile.c
index 01821cc368..dd5973b76d 100644
--- a/time/tzfile.c
+++ b/time/tzfile.c
@@ -600,40 +600,16 @@  __tzfile_compute (__time64_t timer, int use_localtime,
 
   if (use_localtime)
     {
-      __tzname[0] = NULL;
-      __tzname[1] = NULL;
+      unsigned char ti;
 
-      if (__glibc_unlikely (timecnt == 0 || timer < transitions[0]))
+      if (__glibc_unlikely (timecnt == 0 ? tzspec == NULL
+			    : timer < transitions[0]))
 	{
-	  /* TIMER is before any transition (or there are no transitions).
-	     Choose the first non-DST type
-	     (or the first if they're all DST types).  */
-	  i = 0;
-	  while (i < typecnt && types[i].dst)
-	    {
-	      if (__tzname[1] == NULL)
-		__tzname[1] = __tzstring (&zone_names[types[i].idx]);
-
-	      ++i;
-	    }
-
-	  if (i == typecnt)
-	    i = 0;
-	  __tzname[0] = __tzstring (&zone_names[types[i].idx]);
-	  if (__tzname[1] == NULL)
-	    {
-	      tzidx j = i;
-	      while (j < typecnt)
-		if (types[j].dst)
-		  {
-		    __tzname[1] = __tzstring (&zone_names[types[j].idx]);
-		    break;
-		  }
-		else
-		  ++j;
-	    }
+	  /* TIMER is before the first transition; or there are no
+	     transitions and no TZ string.  Use the first type.  */
+	  ti = 0;
 	}
-      else if (timer >= transitions[timecnt - 1])
+      else if (timecnt == 0 || timer >= transitions[timecnt - 1])
 	{
 	  if (__glibc_unlikely (tzspec == NULL))
 	    {
@@ -710,49 +686,19 @@  __tzfile_compute (__time64_t timer, int use_localtime,
 	  i = hi;
 
 	found:
-	  /* assert (timer >= transitions[i - 1]
-	     && (i == timecnt || timer < transitions[i])); */
-	  __tzname[types[type_idxs[i - 1]].dst]
-	    = __tzstring (&zone_names[types[type_idxs[i - 1]].idx]);
-
-	  for (tzidx j = i; j < timecnt; j++)
-	    {
-	      struct ttinfo *ttype = &types[type_idxs[j]];
-	      unsigned char dst = ttype->dst;
-
-	      if (__tzname[dst] == NULL)
-		{
-		  __tzname[dst] = __tzstring (&zone_names[ttype->idx]);
-
-		  if (__tzname[1 - dst] != NULL)
-		    break;
-		}
-	    }
-
-	  if (__glibc_unlikely (__tzname[0] == NULL))
-	    __tzname[0] = __tzname[1];
-
-	  i = type_idxs[i - 1];
+	  ti = type_idxs[i - 1];
 	}
 
-      struct ttinfo *info = &types[i];
-      __daylight = daylight_saved;
-      __timezone = -rule_stdoff;
-
-      if (__tzname[0] == NULL)
-	{
-	  /* This should only happen if there are no transition rules.
-	     In this case there should be only one single type.  */
-	  assert (typecnt == 1);
-	  __tzname[0] = __tzstring (zone_names);
-	}
-      if (__tzname[1] == NULL)
-	/* There is no daylight saving time.  */
-	__tzname[1] = __tzname[0];
-      tp->tm_isdst = info->dst;
-      assert (strcmp (&zone_names[info->idx], __tzname[tp->tm_isdst]) == 0);
-      tp->tm_zone = __tzname[tp->tm_isdst];
+      struct ttinfo *info = &types[ti];
+      unsigned char dst = info->dst;
+      char *tm_zone = __tzstring (&zone_names[info->idx]);
+      tp->tm_isdst = dst;
       tp->tm_gmtoff = info->utoff;
+      tp->tm_zone = tm_zone;
+
+      /* Set tzname[isdst] too; although not required by POSIX or documented,
+	 this is closer to what proleptic TZ does.  */
+      __tzname[dst] = tm_zone;
     }
 
  leap: