A new TZDB release is out — this one updates to IANA TZDB 2026a and ships a handful of bug fixes, some of which have been quietly causing performance problems on Windows for a while.
Get the latest here.
What changed
IANA 2026a
The usual timezone database update — picks up the latest IANA data including rule changes for 2025/2026.
Windows alias lookup — registry I/O on every cache miss
This one’s embarrassing in hindsight. On Windows, when you call GetTimeZone('Europe/Kiev'), the library would:
- Check
CZones— not found (it’s an alias, not a canonical zone) - Call
GetNonLocalizedTZName— a registry lookup across 140+ keys - Fail the registry lookup (Kiev is not a Windows localized name)
- Then check the in-memory
CAliasesarray — and finally find it
Since Europe/Kiev is now a well-known alias for Europe/Kyiv, and the object gets cached under Europe/Kyiv, every subsequent call to GetTimeZone('Europe/Kiev') missed the cache and triggered this entire registry crawl from scratch.
The fix is simple: check CAliases first. If the alias isn’t there, then fall back to the registry as a last resort. This makes alias resolution effectively free (a linear scan of an in-memory array) and relegates the registry to a genuine fallback.
Thanks to Silvestre Pérez for reporting this and providing a detailed analysis.
%z abbreviation for fractional-hour offsets
Pacific/Marquesas sits at UTC-09:30. Its %z abbreviation was rendering as -09-30 instead of -0930. The culprit: when computing the minutes component from a negative delta, (LDelta mod SecsPerHour) div SecsPerMin is itself negative — and passing two negative numbers to Format('%.2d%.2d', ...) produced the extra minus sign.
Fixed by using Abs(LDelta) for both hours and minutes, with the sign emitted explicitly.
Alias keys now cached in GetTimeZone
Related to the first fix: even after resolving Europe/Kiev → Europe/Kyiv, the cached object was only stored under Europe/Kyiv. Subsequent GetTimeZone('Europe/Kiev') calls still missed the cache. The alias input key is now also stored after resolution, so the second call is a straight cache hit.
FinalizeDict was updated for both FPC and Delphi to deduplicate before freeing, since multiple cache keys can now point to the same TBundledTimeZone instance.
That’s it. No API changes, no behavior changes for anyone not hitting these edge cases. If you’re doing batch queries against timezone aliases on Windows, this update should make a noticeable difference.