Skip to content

libast/tm/tminit.c: Fix DST offsets#1008

Open
pghvlaans wants to merge 8 commits into
ksh93:devfrom
pghvlaans:dst_offset
Open

libast/tm/tminit.c: Fix DST offsets#1008
pghvlaans wants to merge 8 commits into
ksh93:devfrom
pghvlaans:dst_offset

Conversation

@pghvlaans

@pghvlaans pghvlaans commented Jul 16, 2026

Copy link
Copy Markdown

RE #976

Pre-u+m code in tminit.c sets the standard (ST) and daylight savings time (DST) offsets by checking times over the previous year of the time requested to compare DST status and offsets from UTC. If no offset change is detected, the DST offset is set equal to the ST offset.

Although assigning the DST offset in this way is counter-intuitive, it does not result in incorrect times being reported so long as two implicit assumptions are met:

  • If the requested time is DST, a change from ST occurred in the previous year.
  • If the offset changed over the previous year, this was the result of a DST transition.

The first assumption fails on musl Linux systems (which would not appear until well after the code in question was written). musl interprets POSIX timezone specifications with a DST name but without rules as being DST year-round. tminit.c therefore calculates both the DST and ST offsets as equal to the overall UTC offset, which is applied twice when reporting times. Because musl apparently disregards the top zoneinfo directory, even common aliases such as PST8PDT return wildly inaccurate results (rather than the one-hour errors that /bin/date would suggest on musl systems).

The second assumption is broken at all times and places between a historical timezone change and a DST shift or one year later, whichever comes first. Although Pacific/Apia between 2011-12-31 and 2012-04-01 yields the most striking results, there are many other examples.

Fixing these problems involves relatively minor changes to tminit.c and related tests:

  • In tminit.c, save and restore the UTC offset and DST status of the requested time; only break offset calculations for a DST shift.
  • In attributes.sh, use full POSIX timezone specifications in lieu of EST5EDT and PST8PDT. This is necessary because musl applies DST for the entire year and the time of the test is ST.
  • In printf.sh, add several TZ tests to account for different combinations of DST and ST designations across historical timezone changes. Also add an EST5EDT test in DST.

@pghvlaans

Copy link
Copy Markdown
Author

Tested on Slackware64 -current (glibc), Void (musl), FreeBSD, OpenBSD, omnios (attributes and printf only) and NetBSD. I don't currently have a macOS VM.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant