From 489e4213a4223a831e2886c324d56e6019188163 Mon Sep 17 00:00:00 2001
From: Kaz Kylheku <kaz@kylheku.com>
Date: Mon, 13 Feb 2023 18:32:42 -0800
Subject: Support gmtoff and zone in time formatting.

The glibc strftime function can refer to the character
string zone, and numeric zone via %Z and %z. So
let us populate these from the Lisp structure.

* time.c (time_fields_to_tm): Take gmtoff and zone
arguments. Store these values in the struct tm,
suitably converted, instead of zeros and nulls.
In the case of zone, we dynamically allocate a utf-8
string, which will have to be freed.
(time_fields_cleanup): New static function.
Called to clean up any allocations performed by
time_fields_to_tm.
(time_struct_to_tm): Drop the strict parameter.
This is useless because the underlying function
time_fields_to_tm checks for nils and substitutes
zeros. This silliness was introduced in a commit
made in 2016.  Extract the gmtoff and zone, passing
these to time_fields_to_tm.
(make_time_impl): Pass nil for gmtoff and zone,
call time_fields_cleanup.
(time_string_meth, time_parse_meth): No need to pass
strict parameter to time_struct_to_tm. Need to call
time_fields_cleanup.
---
 time.c | 42 ++++++++++++++++++++++--------------------
 1 file changed, 22 insertions(+), 20 deletions(-)

diff --git a/time.c b/time.c
index dd2945b5..18a000d7 100644
--- a/time.c
+++ b/time.c
@@ -237,7 +237,8 @@ static void time_fields_to_tm(struct tm *ptm,
                               val year, val month, val day,
                               val hour, val min, val sec,
                               val wday, val yday,
-                              val dst, val self)
+                              val dst, val gmtoff, val zone,
+                              val self)
 {
   uses_or2;
   ptm->tm_year = c_num(or2(year, zero), self) - 1900;
@@ -257,15 +258,21 @@ static void time_fields_to_tm(struct tm *ptm,
     ptm->tm_isdst = 1;
 
 #if HAVE_TM_GMTOFF
-  ptm->TM_GMTOFF = 0;
+  ptm->TM_GMTOFF = c_num(or2(gmtoff, zero), self);
 #endif
 #if HAVE_TM_ZONE
-  ptm->TM_ZONE = 0;
+  ptm->TM_ZONE = if3(zone, utf8_dup_to(c_str(zone, self)), 0);
 #endif
 }
 
-static void time_struct_to_tm(struct tm *ptm, val time_struct, val strict,
-                              val self)
+static void time_fields_cleanup(struct tm *ptm)
+{
+#if HAVE_TM_ZONE
+  free(strip_qual(char *, ptm->TM_ZONE));
+#endif
+}
+
+static void time_struct_to_tm(struct tm *ptm, val time_struct, val self)
 {
   val year = slot(time_struct, year_s);
   val month = slot(time_struct, month_s);
@@ -276,20 +283,11 @@ static void time_struct_to_tm(struct tm *ptm, val time_struct, val strict,
   val wday = slot(time_struct, wday_s);
   val yday = slot(time_struct, yday_s);
   val dst = slot(time_struct, dst_s);
-
-  if (!strict) {
-    year = (year ? year : zero);
-    month = (month ? month : zero);
-    day = (day ? day : zero);
-    hour = (hour ? hour : zero);
-    min = (min ? min : zero);
-    sec = (sec ? sec : zero);
-    wday = (wday ? wday : zero);
-    yday = (yday ? yday : zero);
-  }
+  val gmtoff = slot(time_struct, gmtoff_s);
+  val zone = slot(time_struct, zone_s);
 
   time_fields_to_tm(ptm, year, month, day, hour, min, sec,
-                    wday, yday, dst, self);
+                    wday, yday, dst, gmtoff, zone, self);
 }
 
 static val make_time_impl(time_t (*pmktime)(struct tm *),
@@ -301,8 +299,9 @@ static val make_time_impl(time_t (*pmktime)(struct tm *),
   time_t time;
 
   time_fields_to_tm(&local, year, month, day,
-                    hour, minute, second, nil, nil, isdst, self);
+                    hour, minute, second, nil, nil, isdst, nil, nil, self);
   time = pmktime(&local);
+  time_fields_cleanup(&local);
 
   return time == -1 ? nil : num_time(time);
 }
@@ -426,12 +425,13 @@ static val time_string_meth(val time_struct, val format)
   char buffer[512] = "";
   char *fmt = utf8_dup_to(c_str(format, self));
 
-  time_struct_to_tm(&tms, time_struct, t, self);
+  time_struct_to_tm(&tms, time_struct, self);
 
   if (strftime(buffer, sizeof buffer, fmt, &tms) == 0)
     buffer[0] = 0;
 
   free(fmt);
+  time_fields_cleanup(&tms);
 
   return string_own(utf8_dup_from(buffer));
 }
@@ -444,7 +444,7 @@ static val time_parse_meth(val time_struct, val format, val string)
   struct tm tms = all_zero_init;
   val ret = nil;
 
-  time_struct_to_tm(&tms, time_struct, nil, self);
+  time_struct_to_tm(&tms, time_struct, self);
 
   {
     const wchar_t *w_str = c_str(string, self);
@@ -462,6 +462,8 @@ static val time_parse_meth(val time_struct, val format, val string)
     free(str);
   }
 
+  time_fields_cleanup(&tms);
+
   return ret;
 }
 
-- 
cgit v1.2.3