]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix DST time calculations on MS-Windows
authorEli Zaretskii <eliz@gnu.org>
Mon, 26 May 2025 16:53:21 +0000 (19:53 +0300)
committerEshel Yaron <me@eshelyaron.com>
Tue, 27 May 2025 14:34:49 +0000 (16:34 +0200)
* src/w32.c (w32_fix_tzset): New function.
* src/timefns.c (emacs_localtime_rz, tzlookup):
* src/w32.c (sys_localtime): Call 'w32_fix_tzset'.
(Bug#11281)

(cherry picked from commit 3b5226af3f737c82f9bbedd8fbe067bab4b4b67a)

src/timefns.c
src/w32.c
src/w32.h

index 4d296ff8dcdd612d7263b426a2895b7a7df07b51..8cf424bbe7e7a44fae99cc8d1e86e27d2b013a4f 100644 (file)
@@ -189,6 +189,7 @@ emacs_localtime_rz (timezone_t tz, time_t const *t, struct tm *tm)
      display-time) are in real danger of missing timezone and DST
      changes.  Calling tzset before each localtime call fixes that.  */
   tzset ();
+  w32_fix_tzset ();
 #endif
   tm = localtime_rz (tz, t, tm);
   if (!tm && errno == ENOMEM)
@@ -306,6 +307,9 @@ tzlookup (Lisp_Object zone, bool settz)
       block_input ();
       emacs_setenv_TZ (zone_string);
       tzset ();
+#ifdef WINDOWSNT
+      w32_fix_tzset ();
+#endif
       timezone_t old_tz = local_tz;
       local_tz = new_tz;
       tzfree (old_tz);
index 5de721ad71f910011d96d91e0b7711792a9da220..9e17c2e5fbb7afbd577092ae02675b7f8223041b 100644 (file)
--- a/src/w32.c
+++ b/src/w32.c
@@ -10289,6 +10289,30 @@ w32_read_registry (HKEY rootkey, Lisp_Object lkey, Lisp_Object lname)
 }
 
 \f
+/* mingw.org's MinGW doesn't declare _dstbias.  MinGW64 defines it as a
+   macro.  */
+#ifndef _dstbias
+__MINGW_IMPORT int _dstbias;
+#endif
+
+/* Fix a bug in MS implementation of 'tzset'.  This function should be
+   called immediately after 'tzset'.  */
+void
+w32_fix_tzset (void)
+{
+  char *tz_env = getenv ("TZ");
+
+  /* When TZ is defined in the environment, '_tzset' updates _daylight,
+     but not _dstbias.  Then if we are switching from a timezone without
+     DST to a timezone with DST, 'localtime' and friends will apply zero
+     DST bias, which is incorrect. (When TZ is not defined, '_tzset'
+     does update _dstbias using values obtained from Windows API
+     GetTimeZoneInformation.)  Here we fix that blunder by detecting
+     this situation and forcing _dstbias to be 1 hour.  */
+  if (tz_env && _daylight && !_dstbias)
+    _dstbias = -3600;
+}
+
 /* The Windows CRT functions are "optimized for speed", so they don't
    check for timezone and DST changes if they were last called less
    than 1 minute ago (see http://support.microsoft.com/kb/821231).  So
@@ -10299,6 +10323,7 @@ struct tm *
 sys_localtime (const time_t *t)
 {
   tzset ();
+  w32_fix_tzset ();
   return localtime (t);
 }
 
index ae3999ffcfd133a06ecdea7c6b3a606da051c735..9d9887ec782219f68659e20b6e048d800b0b78cb 100644 (file)
--- a/src/w32.h
+++ b/src/w32.h
@@ -234,6 +234,7 @@ extern int openat (int, const char *, int, int);
 extern int fchmodat (int, char const *, mode_t, int);
 extern int lchmod (char const *, mode_t);
 extern bool symlinks_supported (const char *);
+extern void w32_fix_tzset (void);
 
 
 /* Return total and free memory info.  */