The first patch is a prerequisite to fixing a GNU coreutils bug. It adds
a posixtime_z function which operates on a timezone_t instead of the TZ
environment variable.

The second patch adjusts the tests to use posixtime_z (NULL, ...),
instead of setting the TZ environment variable.

I'll push them tomorrow, unless anyone notices issues, of course.

Collin

>From 13d584a701a6a0cef54a9c19a107417ae6753fc3 Mon Sep 17 00:00:00 2001
Message-ID: <13d584a701a6a0cef54a9c19a107417ae6753fc3.1792649557.git.collin.fu...@gmail.com>
From: Collin Funk <[email protected]>
Date: Wed, 21 Oct 2026 22:52:06 -0700
Subject: [PATCH 1/2] posixtm: Add posixtime_z which operates on a timezone_t.

* lib/posixtm.c: Include stdlib.h.
(year): Perform operations on a timezone_t argument.
(posix_time_parse): Likewise.
(posixtime_z): New function, based on the previous posixtime function
but operating on a timezone_t.
(posixtime): Implement in terms of posixtime_z.
* lib/posixtm.h (posixtime_z): New declaration.
* modules/posixtm (Depends-on): Add time_rz.
---
 ChangeLog       | 12 ++++++++++++
 lib/posixtm.c   | 29 +++++++++++++++++++++--------
 lib/posixtm.h   |  2 ++
 modules/posixtm |  1 +
 4 files changed, 36 insertions(+), 8 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 70b2d84fde..a9a292f2a9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2026-10-21  Collin Funk  <[email protected]>
+
+	posixtm: Add posixtime_z which operates on a timezone_t.
+	* lib/posixtm.c: Include stdlib.h.
+	(year): Perform operations on a timezone_t argument.
+	(posix_time_parse): Likewise.
+	(posixtime_z): New function, based on the previous posixtime function
+	but operating on a timezone_t.
+	(posixtime): Implement in terms of posixtime_z.
+	* lib/posixtm.h (posixtime_z): New declaration.
+	* modules/posixtm (Depends-on): Add time_rz.
+
 2026-10-21  Bruno Haible  <[email protected]>
 
 	Avoid -Wundef warnings about __clang_major__ with recent GCC in C mode.
diff --git a/lib/posixtm.c b/lib/posixtm.c
index b5bb7afe9c..f6348fe786 100644
--- a/lib/posixtm.c
+++ b/lib/posixtm.c
@@ -27,6 +27,7 @@
 #include "verify.h"
 
 #include <stdckdint.h>
+#include <stdlib.h>
 #include <string.h>
 
 /*
@@ -47,7 +48,8 @@
 */
 
 static bool
-year (struct tm *tm, const int *digit_pair, idx_t n, unsigned int syntax_bits)
+year (timezone_t tz, struct tm *tm, const int *digit_pair, idx_t n,
+      unsigned int syntax_bits)
 {
   switch (n)
     {
@@ -74,7 +76,8 @@ year (struct tm *tm, const int *digit_pair, idx_t n, unsigned int syntax_bits)
       {
         /* Use current year.  */
         time_t now = time (NULL);
-        struct tm *tmp = localtime (&now);
+        struct tm tm_year;
+        struct tm *tmp = localtime_rz (tz, &now, &tm_year);
         if (! tmp)
           return false;
         tm->tm_year = tmp->tm_year;
@@ -89,7 +92,8 @@ year (struct tm *tm, const int *digit_pair, idx_t n, unsigned int syntax_bits)
 }
 
 static bool
-posix_time_parse (struct tm *tm, const char *s, unsigned int syntax_bits)
+posix_time_parse (timezone_t tz, struct tm *tm, const char *s,
+                  unsigned int syntax_bits)
 {
 
   idx_t s_len = strlen (s);
@@ -123,7 +127,7 @@ posix_time_parse (struct tm *tm, const char *s, unsigned int syntax_bits)
   int *p = pair;
   if (! (syntax_bits & PDS_TRAILING_YEAR))
     {
-      if (! year (tm, p, len - 4, syntax_bits))
+      if (! year (tz, tm, p, len - 4, syntax_bits))
         return false;
       p += len - 4;
       len = 4;
@@ -139,7 +143,7 @@ posix_time_parse (struct tm *tm, const char *s, unsigned int syntax_bits)
   /* Handle any trailing year.  */
   if (syntax_bits & PDS_TRAILING_YEAR)
     {
-      if (! year (tm, p, len, syntax_bits))
+      if (! year (tz, tm, p, len, syntax_bits))
         return false;
     }
 
@@ -157,11 +161,11 @@ posix_time_parse (struct tm *tm, const char *s, unsigned int syntax_bits)
 /* Parse a POSIX-style date, returning true if successful.  */
 
 bool
-posixtime (time_t *p, const char *s, unsigned int syntax_bits)
+posixtime_z (timezone_t tz, time_t *p, const char *s, unsigned int syntax_bits)
 {
   struct tm tm0;
 
-  if (! posix_time_parse (&tm0, s, syntax_bits))
+  if (! posix_time_parse (tz, &tm0, s, syntax_bits))
     return false;
 
   bool leapsec = false;
@@ -176,7 +180,7 @@ posixtime (time_t *p, const char *s, unsigned int syntax_bits)
       tm1.tm_year = tm0.tm_year;
       tm1.tm_wday = -1;
       tm1.tm_isdst = -1;
-      time_t t = mktime (&tm1);
+      time_t t = mktime_z (tz, &tm1);
 
       if (tm1.tm_wday < 0)
         return false;
@@ -207,3 +211,12 @@ posixtime (time_t *p, const char *s, unsigned int syntax_bits)
       leapsec = true;
     }
 }
+
+bool
+posixtime (time_t *p, const char *s, unsigned int syntax_bits)
+{
+  timezone_t const tz = tzalloc (getenv ("TZ"));
+  if (! tz)
+    return false;
+  return posixtime_z (tz, p, s, syntax_bits);
+}
diff --git a/lib/posixtm.h b/lib/posixtm.h
index 6c166dadb5..8bb023227b 100644
--- a/lib/posixtm.h
+++ b/lib/posixtm.h
@@ -39,6 +39,8 @@ extern "C" {
 #define PDS_LEADING_YEAR 0
 
 bool posixtime (time_t *p, const char *s, unsigned int syntax_bits);
+bool posixtime_z (timezone_t tz, time_t *p, const char *s,
+                  unsigned int syntax_bits);
 
 
 #ifdef __cplusplus
diff --git a/modules/posixtm b/modules/posixtm
index e86912247c..84bccc42e3 100644
--- a/modules/posixtm
+++ b/modules/posixtm
@@ -13,6 +13,7 @@ mktime
 bool
 stdckdint-h
 time
+time_rz
 verify
 
 configure.ac:
-- 
2.56.0

>From e2e40c9453074ba5aa19e5bd99cdbf5315060f09 Mon Sep 17 00:00:00 2001
Message-ID: <e2e40c9453074ba5aa19e5bd99cdbf5315060f09.1792649557.git.collin.fu...@gmail.com>
In-Reply-To: <13d584a701a6a0cef54a9c19a107417ae6753fc3.1792649557.git.collin.fu...@gmail.com>
References: <13d584a701a6a0cef54a9c19a107417ae6753fc3.1792649557.git.collin.fu...@gmail.com>
From: Collin Funk <[email protected]>
Date: Wed, 21 Oct 2026 23:06:20 -0700
Subject: [PATCH 2/2] posixtm tests: Use posixtime_z instead of setting TZ.

* tests/test-posixtm.c (main): Operate on a NULL timezone_t instead of
modifying environment variables.
---
 ChangeLog            |  4 ++++
 tests/test-posixtm.c | 17 ++++++-----------
 2 files changed, 10 insertions(+), 11 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index a9a292f2a9..317fdd8a13 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
 2026-10-21  Collin Funk  <[email protected]>
 
+	posixtm tests: Use posixtime_z instead of setting TZ.
+	* tests/test-posixtm.c (main): Operate on a NULL timezone_t instead of
+	modifying environment variables.
+
 	posixtm: Add posixtime_z which operates on a timezone_t.
 	* lib/posixtm.c: Include stdlib.h.
 	(year): Perform operations on a timezone_t argument.
diff --git a/tests/test-posixtm.c b/tests/test-posixtm.c
index 002aa705cb..3c42998890 100644
--- a/tests/test-posixtm.c
+++ b/tests/test-posixtm.c
@@ -119,20 +119,15 @@ int
 main (void)
 {
   char curr_year_str[30];
-  struct tm *tm;
   time_t t_now;
-  int err;
   size_t n_bytes;
 
-  /* The above test data requires Universal Time, e.g., TZ="UTC0".  */
-  err = setenv ("TZ", "UTC0", 1);
-  ASSERT (err == 0);
-
   t_now = time (NULL);
   ASSERT (t_now != (time_t) -1);
-  tm = localtime (&t_now);
-  ASSERT (tm);
-  n_bytes = strftime (curr_year_str, sizeof curr_year_str, "%Y", tm);
+  struct tm tm;
+  struct tm *tm_ptr = localtime_rz (NULL, &t_now, &tm);
+  ASSERT (tm_ptr);
+  n_bytes = strftime (curr_year_str, sizeof curr_year_str, "%Y", &tm);
   ASSERT (0 < n_bytes);
 
   for (unsigned int i = 0; T[i].in; i++)
@@ -168,10 +163,10 @@ main (void)
         {
           char tmp_buf[20];
           stpcpy (stpcpy (tmp_buf, curr_year_str), T[i].in);
-          ASSERT (posixtime (&t_exp, tmp_buf, T[i].syntax_bits));
+          ASSERT (posixtime_z (NULL, &t_exp, tmp_buf, T[i].syntax_bits));
         }
 
-      ok = posixtime (&t_out, T[i].in, T[i].syntax_bits);
+      ok = posixtime_z (NULL, &t_out, T[i].in, T[i].syntax_bits);
       if (ok != !!T[i].valid)
         {
           printf ("%s return value mismatch: got %d, expected %d\n",
-- 
2.56.0

Reply via email to