+static struct tm *
+emacs_localtime_rz (timezone_t tz, time_t const *t, struct tm *tm)
+{
+ tm = localtime_rz (tz, t, tm);
+ if (!tm && errno == ENOMEM)
+ memory_full (SIZE_MAX);
+ return tm;
+}
+
+static time_t
+emacs_mktime_z (timezone_t tz, struct tm *tm)
+{
+ errno = 0;
+ time_t t = mktime_z (tz, tm);
+ if (t == (time_t) -1 && errno == ENOMEM)
+ memory_full (SIZE_MAX);
+ return t;
+}
+
+/* Allocate a timezone, signaling on failure. */
+static timezone_t
+xtzalloc (char const *name)
+{
+ timezone_t tz = tzalloc (name);
+ if (!tz)
+ memory_full (SIZE_MAX);
+ return tz;
+}
+
+/* Free a timezone, except do not free the time zone for local time.
+ Freeing utc_tz is also a no-op. */
+static void
+xtzfree (timezone_t tz)
+{
+ if (tz != local_tz)
+ tzfree (tz);
+}
+
+/* Convert the Lisp time zone rule ZONE to a timezone_t object.
+ The returned value either is 0, or is LOCAL_TZ, or is newly allocated.
+ If SETTZ, set Emacs local time to the time zone rule; otherwise,
+ the caller should eventually pass the returned value to xtzfree. */
+static timezone_t
+tzlookup (Lisp_Object zone, bool settz)
+{
+ static char const tzbuf_format[] = "XXX%s%"pI"d:%02d:%02d";
+ char tzbuf[sizeof tzbuf_format + INT_STRLEN_BOUND (EMACS_INT)];
+ char const *zone_string;
+ timezone_t new_tz;
+
+ if (NILP (zone))
+ return local_tz;
+ else if (EQ (zone, Qt))
+ {
+ zone_string = "UTC0";
+ new_tz = utc_tz;
+ }
+ else
+ {
+ if (EQ (zone, Qwall))
+ zone_string = 0;
+ else if (STRINGP (zone))
+ zone_string = SSDATA (zone);
+ else if (INTEGERP (zone))
+ {
+ EMACS_INT abszone = eabs (XINT (zone)), hour = abszone / (60 * 60);
+ int min = (abszone / 60) % 60, sec = abszone % 60;
+ sprintf (tzbuf, tzbuf_format, &"-"[XINT (zone) < 0], hour, min, sec);
+ zone_string = tzbuf;
+ }
+ else
+ xsignal2 (Qerror, build_string ("Invalid time zone specification"),
+ zone);
+ new_tz = xtzalloc (zone_string);
+ }
+
+ if (settz)
+ {
+ block_input ();
+ emacs_setenv_TZ (zone_string);
+ timezone_t old_tz = local_tz;
+ local_tz = new_tz;
+ tzfree (old_tz);
+ unblock_input ();
+ }
+
+ return new_tz;
+}
+