GNU bug report logs -
#11281
DST has not effect on windows XP when system DST adjustment is disabled
Previous Next
Full log
View this message in rfc822 format
> Cc: 11281 <at> debbugs.gnu.org, stefankangas <at> gmail.com
> Date: Sun, 25 May 2025 18:51:06 +0300
> From: Eli Zaretskii <eliz <at> gnu.org>
>
> > Date: Mon, 26 May 2025 00:08:23 +0900
> > From: Kazuhiro Ito <kzhr <at> d1.dion.ne.jp>
> > Cc: 11281 <at> debbugs.gnu.org, stefankangas <at> gmail.com
> >
> > > > > JST-9
> > > > > _daylight = 0
> > > > > _timezone = -32400
> > > > > _tzname[0] = JST
> > > > > _dstbias = -3600
> > >
> > > Isn't this result strange? If a timezone has no DST, why is _dstbias
> > > not zero?
> >
> > I feel it is strange, too. My understanding is that tzset does not
> > touch _dstbias when timezone is specified by TZ environmental variable
> > and it is the bug. However when _daylight is zero, _dstbias value is
> > not used and the issue doesn't become prominent.
>
> If tzset doesn't touch _dstbias, the results begin to make sense,
> because it means _dstbias is left at its value determine by previous
> calls, and does not necessarily correspond to the timezone set by the
> call to tzset. But if that is the case, we should correct this bug by
> examining the value of TZ and assigning to _dstbias the value of
> either -3600 or zero, depending on whether the value of TZ does or
> doesn't specify the "DST" part. IOW, blindly "correcting" the zero
> value of _dstbias is not right; we should instead go by the DST
> definition of the value in TZ.
I think I see the problem: when TZ is defined in the environment,
tzset updates _daylight, but doesn't touch _dstbias. So if you start
from a timezone without DST and then switch to a timezone with DST,
_dstbias stays zero, and local time is computed incorrectly.
Therefore, I suggest the patches below. Could you please try them?
> See above: I think I changed my mind, and we should set _dstbias
> according to the actual value of TZ, and only if TZ is indeed set
The patches below implement this, by using _daylight as the evidence
that TZ defines DST.
diff --git a/src/timefns.c b/src/timefns.c
index 4d296ff..8cf424b 100644
--- a/src/timefns.c
+++ b/src/timefns.c
@@ -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);
diff --git a/src/w32.c b/src/w32.c
index 5de721a..a98a008 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -10289,6 +10289,30 @@ w32_read_registry (HKEY rootkey, Lisp_Object lkey, Lisp_Object lname)
}
+/* 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', to 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 @@ w32_read_registry (HKEY rootkey, Lisp_Object lkey, Lisp_Object lname)
sys_localtime (const time_t *t)
{
tzset ();
+ w32_fix_tzset ();
return localtime (t);
}
diff --git a/src/w32.h b/src/w32.h
index ae3999f..9d9887e 100644
--- a/src/w32.h
+++ b/src/w32.h
@@ -234,6 +234,7 @@ #define FILE_DONT_CLOSE 0x1000
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. */
This bug report was last modified 17 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.