Skip to content

gh-161194: find time.altzone by searching DST offset in current year - #161338

Open
nascheme wants to merge 6 commits into
python:mainfrom
nascheme:gh-161194-tz-libc-globals
Open

nascheme wants to merge 6 commits into
python:mainfrom
nascheme:gh-161194-tz-libc-globals

Conversation

@nascheme

@nascheme nascheme commented Nov 4, 2026 •

Copy link
Copy Markdown
Member

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.

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.
Comment thread Modules/timemodule.c Outdated
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);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
@read-the-docs-community

read-the-docs-community Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

Documentation build overview

📚 cpython-previews | 🛠️ Build #35678613 | 📁 Comparing 7fad7cb against main (5346059)

  🔍 Preview build  

2 files changed
± library/time.html
± whatsnew/changelog.html

@nascheme nascheme changed the title gh-161194: Use libc timezone variables for time module constants gh-161194: find time.altzone by searching DST offset in current year Nov 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting core review type-bug An unexpected behavior, bug, or error

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants