Repository navigation
Conversation
Previously the libc path in init_timezone() was gated on HAVE_DECL_TZNAME, which configure only defines when struct tm lacks tm_zone. On Linux and macOS this meant timezone, altzone, daylight and tzname were guessed by sampling localtime() near January 1 and July 1 of the current year. That gives stale values when a zone's rules change mid-year (e.g. America/Vancouver moving to permanent MST on 2026-11-01) and wrong standard/DST names for negative DST zones. Add a configure check, HAVE_TIMEZONE_GLOBALS, that verifies timezone, daylight and tzname are usable as variables, and use libc's values whenever it is defined. FreeBSD, where timezone is a function, keeps the sampling fallback. When libc has no altzone, use timezone - 3600 only if daylight is set, otherwise timezone.
| ADD_INT("altzone", _Py_timezone-3600); | ||
| /* libc does not provide the DST offset. Assume a one hour shift when | ||
| the zone has DST, otherwise use the standard offset. */ | ||
| ADD_INT("altzone", _Py_daylight ? _Py_timezone - 3600 : _Py_timezone); |
There was a problem hiding this comment.
In glibc daylight does not mean "this zone has DST now", it means DST appears somewhere in the zone's transition history. The glibc manual says:
This variable is nonzero if daylight saving time rules apply. A nonzero value does not necessarily mean that daylight saving time is now in effect; it means only that daylight saving time is sometimes in effect. This variable has little or no practical use; it is present for POSIX compatibility.
There was a problem hiding this comment.
Oh, that's too bad. I pushed a change that uses a sampling approach (look at dates this year looking for DST offset). I'm not thrilled about that solution but I can't think of a better one.
We can't use the _Py_daylight flag to determine the DST offset, it only says if the zone has DST rules. Loop through the current year months, looking for DST offset.
Documentation build overview
|
The libc path in init_timezone() was gated on HAVE_DECL_TZNAME, which configure only checks when struct tm lacks tm_zone. On Linux and macOS, this caused timezone constants to be estimated from January and July samples, producing stale values after mid-year rule changes and incorrect standard/DST classification for negative DST zones.
Add _Py_HAVE_TIMEZONE_GLOBALS to detect and use libc’s timezone, daylight, and tzname variables. Platforms without these globals retain the existing fallback.
When libc lacks altzone, estimate it using calendar-month samples rather than assuming a one-hour DST shift. Prefer the latest sampled DST offset at or before now, looking ahead only if none was found. Sampling is best-effort: failures retain the last valid offset, or the standard offset if none was found.
Note: creation of this PR was assisted by an LLM.