The IANA Time Zone Database (tzdb, also called tz or zoneinfo) is a volunteer maintained set of text files that records every government's clock rules since 1970. A coordinator turns each announced change into a release such as 2026e, and that release reaches your servers, phones and code only when an operating system, runtime or package update carries it.
That last step is where things go wrong. On Sunday 25 October 2026 the United Kingdom and the European Union moved their clocks back an hour, a week before the US change on Sunday 1 November. This year the North American change is less routine than usual: four Canadian jurisdictions have moved to permanent standard offsets in 2026, so a device with stale time zone data will fall back on 1 November in places where the clocks are not supposed to move at all. This post explains how the database works, how a rule change travels from a legislature to your process, and how to find every copy of time zone data you ship.
For cron jobs and scheduled agents across the change, see our post on daylight saving time and scheduled AI tasks; this one does not repeat it, and takes no position on whether daylight saving time should exist. Every rule, date and version below comes from the IANA tz files and release notes, the IETF RFCs, US law and NIST, or the named platform's own documentation.
Key takeaways
- The tz database is two things: tzdata, human readable text files of zones, rules and links, and tzcode, the reference C code plus the
ziccompiler that turns the text into binary TZif files. - It has been hosted by IANA since 2012 under RFC 6557 (BCP 175). A TZ Coordinator decides changes in consultation with the public tz@iana.org mailing list and does not set policy for any country.
- Releases are named by year plus a letter. 2026 has had five so far: 2026a (1 March), 2026b (22 April), 2026c (8 July), 2026d (11 September) and 2026e (29 September).
- The compiled format is TZif, now specified by RFC 9636 (October 2024), which obsoleted RFC 8536.
- One host often carries several independent copies (OS files, a Java runtime's own data, ICU inside Node.js and browsers, Python's
tzdatapackage, Go's embedded data, JavaScript libraries) that update on different schedules and can disagree. - British Columbia, Alberta, the Northwest Territories and Manitoba all moved to permanent standard offsets in 2026. Data older than 2026b, 2026c, 2026d and 2026e respectively will move their clocks back on 1 November 2026 when it should not.
- Store and log in UTC (RFC 3339), convert at the edge, and treat tzdata as a dependency in your SBOM.
What is the tz database?
IANA's own summary is short: the database "contains code and data that represent the history of local time for many representative locations worldwide," and it is updated "to reflect changes made by political bodies to time zone boundaries, UTC offsets, and daylight-saving rules." It is aimed at software implementers. As the IANA page puts it, end users "typically receive updates to this data through their software and operating system vendors."
tzdata and tzcode
A release ships as two tarballs and a combined one, all on data.iana.org:
| File | What it holds |
|---|---|
tzdataV.tar.gz | The data: source files named for regions (africa, antarctica, asia, australasia, europe, northamerica, southamerica, etcetera, backward), plus tables such as zone1970.tab and a version file |
tzcodeV.tar.gz | The reference code: zic (the compiler), zdump (a dumper for checking transitions) and localtime.c, a reference implementation of the C and POSIX time functions |
tzdb-V.tar.lz | Both, in one lzip compressed archive |
Here V is the version. According to the tz-link page, every version since 1996 has been "a four-digit year followed by lower-case letter," running a to z, then za to zz, and so on. Since 2016h every release has a text file named version whose first line is the version string, and since 2012e every release has been tagged in the development repository at github.com/eggert/tz. Untagged commits, tz-link warns, "are less well tested and probably contain more errors."
Zones, rules and links
The text files use three main line types. A Rule line describes a recurring daylight saving pattern. A Zone line describes the history of one location: its offset from UT, which rule set applies, the abbreviation format and when each period ends. A Link line makes an old or alternative name point to a canonical zone.
The two rules that matter most this month look like this in the current source files:
# europe
Rule EU 1981 max - Mar lastSun 1:00u 1:00 S
Rule EU 1996 max - Oct lastSun 1:00u 0 -
# northamerica
Rule US 2007 max - Mar Sun>=8 2:00 1:00 D
Rule US 2007 max - Nov Sun>=1 2:00 0 S
Read the EU line as: from 1996 with no end year, on the last Sunday of October at 01:00 UT (the u suffix), save zero hours. That is why London, Paris and Berlin all changed at the same instant on 25 October 2026, 01:00 UTC, even though their local clock times differed. The US lines say: from 2007 onward, save one hour from the first Sunday on or after 8 March at 02:00 local time until the first Sunday on or after 1 November at 02:00. That matches the statute, 15 U.S.C. 260a, which runs daylight saving time from "2 o'clock antemeridian on the second Sunday of March" to the same hour "on the first Sunday of November." NIST gives the 2026 dates as 8 March and 1 November, both at 2 a.m. local time.
Here is the zone entry for Vancouver from the same northamerica file, which shows how a 2026 change is recorded:
Zone America/Vancouver -8:12:28 - LMT 1884
-8:00 Vanc P%sT 1987
-8:00 Canada P%sT 2026 Mar 9
# Temporary hack; see above.
-8:00 Canada PDT 2026 Nov 1 2:00
# End of temporary hack.
-7:00 - MST
Each continuation line is a period. The last line has no end date: from 1 November 2026 at 02:00, Vancouver is at a fixed UTC minus 7 with no rule set, abbreviated MST. The "temporary hack" comment is explained below.
Area/Location names
Zone names follow an Area/Location pattern. The theory and pragmatics document says the Area "is a continent or ocean," the Location "is a specific location within the area," and North and South America share the Area America. Typical names are Africa/Cairo, America/New_York and Pacific/Honolulu. Some get an extra level to avoid confusion, such as America/Indiana/Petersburg.
The naming goals are deliberate. Names "are typically not tied to countries," so a country renaming itself or a city changing countries does not break software. Each main entry aims to identify a region whose clocks have agreed since 1970, which is why there is an America/Phoenix (most of Arizona, no DST) separate from America/Denver. Old names, such as US/Eastern or Canada/Pacific, survive as links in the backward file so that configurations written decades ago still resolve.
One naming trap: Etc/GMT+5 style names use POSIX signs, which the tz etcetera file notes are "positive signs west of Greenwich," so Etc/GMT+5 means five hours behind UTC.
Who maintains it, and how did it move to IANA?
For decades the database lived on a mailing list hosted at the US National Institutes of Health. RFC 6557, published in February 2012 as BCP 175 by Eliot Lear and Paul Eggert, records that history: Arthur David Olson had "maintained the database, coordinated the mailing list, and provided a release platform since the database's inception," and with his retirement approaching the time zone community asked the IETF to take over its upkeep. The RFC also notes the database was then "updated approximately twenty times per year, depending on the year." Recent years have had fewer releases than that.
RFC 6557 sets out a small process:
- TZ Coordinator. The person or people who maintain the data and code, manage releases and run the mailing list. The coordinator is an IANA Designated Expert, "empowered to decide, as the designated expert, appropriate changes," taking list views into account, and decides when releases happen.
- The tz mailing list. Discussion and submissions go to the public tz@iana.org list. Release announcements also go to tz-announce@iana.org, a low traffic list that operators should subscribe to.
- No policy role. The coordinator "SHALL NOT set time zone policy for a region." Changes reflect "the consensus on the ground."
- Succession. The RFC describes how a coordinator is selected or replaced, so the work does not depend on one volunteer.
The tz-link page adds that "the tz code and data are by no means authoritative" and asks that changes cite the legislation or regulation so the exact transition times can be checked.
How does a government's DST change become a tzdata release?
The path from a legislature to a laptop has more hops than most people expect.
| Step | Who acts | What happens | Typical delay |
|---|---|---|---|
| 1. Decision | A government or regulator | Passes a law, order or regulation that changes an offset or DST rule | Varies; sometimes weeks before the change |
| 2. Report | Anyone, often a local contributor | Emails tz@iana.org with a link to the official text | Hours to days |
| 3. Proposal | TZ Coordinator and list | Discusses the reading of the law, drafts a patch to the text files, often with commentary | Days |
| 4. Release | TZ Coordinator | Tags and publishes a new version (for example 2026e) and posts to tz-announce | No fixed schedule |
| 5. Downstream packaging | OS distributions, runtime projects, ICU, CLDR, language package maintainers | Rebuild their own formats, test and publish updates | Days to months |
| 6. Rollout | Device makers, cloud images, your build pipeline | Ship OS updates, runtime patches, new container images and app releases | Weeks to never, for unsupported devices |
| 7. Pickup | Your hosts, containers and apps | Install the update and restart or rebuild whatever loaded the old data | Depends on you |
The tz-link page is plain about timing. "There is no fixed schedule for tzdb releases," downstream parties must "integrate, test, and roll out an update before end users see changes," and "older devices may no longer be supported and thus may never be updated." So it asks governments to announce changes "at least a year before" they take effect, warning that "the shorter the notice, the more likely clock problems will arise."
Why short notice causes problems: 2026 as a worked example
The 2026 release notes, in the NEWS file, read like a case study in short notice.
| Release | Date | Headline change (from NEWS) |
|---|---|---|
| 2026a | 1 Mar 2026 | Moldova has used EU transition times since 2022; the "right" leap second files are no longer installed by default; several integer overflow bugs fixed |
| 2026b | 22 Apr 2026 | British Columbia moved to permanent minus 07 on 9 March 2026; zic fix for a last transition to a new time type |
| 2026c | 8 Jul 2026 | Alberta moved to permanent minus 06 on 18 June 2026; Morocco moves to permanent plus 00 on 20 September 2026 |
| 2026d | 11 Sep 2026 | Northwest Territories moved to permanent minus 06 on 21 August 2026; security, performance and porting fixes in zic and localtime |
| 2026e | 29 Sep 2026 | Manitoba moves to permanent minus 05 on 31 October 2026 |
Alberta's change took legal effect on 18 June and shipped on 8 July; the Northwest Territories change took effect on 21 August and shipped on 11 September. Manitoba's was released on 29 September for a legal date of 31 October. The 2026e notes say that "given the short leadtime with Manitoba's announcement," the coordinator assumed the parts of northwestern Ontario that historically follow Winnipeg would follow again, "to avoid creating new zones that may not be needed," and warned that "another TZDB release may be needed soon" if they do not.
All of these still have to pass steps 5 to 7 before 1 November 2026, the first date on which old and new data give different UTC offsets for these zones. A month is not long for a phone maker or an enterprise patch cycle.
The temporary hack, and why it matters to you
The four Canadian changes are modeled in an unusual way. Although British Columbia's change legally took place on 9 March 2026, the data "temporarily model[s] the change to occur on 2026-11-01 at 02:00 instead." The 2026b notes say this "works around a limitation in CLDR 48.1 (2026-01-08)," the Unicode locale data many platforms use for time zone display names, and that the hack is "planned to be removed after CLDR is fixed." Alberta, the Northwest Territories and Manitoba follow the same pattern.
In practice the UTC offset is the same either way through the summer (daylight time at minus 7 in Vancouver equals the new permanent minus 7). What differs is the abbreviation and the isdst flag until 1 November, and then, crucially, whether the clock moves back. With current data it does not. With data older than the relevant release it does.
There is a second, subtler catch in the 2026b notes. The hack exposed a bug in older versions of zic: versions 2023d through 2026a, in their default "slim" output mode, generate a TZif file that "violates Internet RFC 9636 §3.3," which causes "some TZif readers, including tzcode itself, to ignore America/Vancouver's 2026-11-01 02:00 transition from PDT (tm_isdst=1) to MST (tm_isdst=0)." The notes say no known reader mishandles the UT offsets, but they advise caution and give the workaround: compile with zic -b fat. If you build your own zoneinfo files from new data with an old compiler, for example in a minimal container image build, check which zic you use.
The 2026d notes add another wrinkle: the hacks were adjusted to work around a libstdc++ std::chrono bug in several GCC releases (GCC bug 124851). Time zone data has more consumers than most teams realise, and each can have its own bugs.
It is not only data
Many tz releases also change tzcode. The 2026 notes list fixes for integer overflows in zic on "outlandish input," a buffer overflow when generating certain TZ strings "which can occur with adversarial input," and a change so that tzset fails cleanly on an oversized TZif file instead of "silently ignoring excess parts of the file." Most systems use their own C library's TZif reader rather than IANA's localtime.c, but anything that compiles or parses TZif from untrusted input is a parser like any other and should be kept current.
What is the TZif format, and where does it live?
TZif, RFC 9636
The text source is compiled by zic into one binary file per zone in the Time Zone Information Format. RFC 9636, published in October 2024 by Arthur David Olson, Paul Eggert and Ken Murchison, specifies it and "replaces and obsoletes RFC 8536." It also registers two media types, application/tzif and application/tzif-leap, so the files can be exchanged between systems.
The structure, in plain terms:
- Header. Every file starts with the four ASCII bytes
TZifand a version byte: NUL for version 1, then2,3or4. The tzfile(5) manual page describes a 44 byte header with counts of transitions, local time types, abbreviation characters and leap second records. - Version 1 data block. Transition times as 32 bit integers. RFC 9636 notes these "are limited to representing time changes from 1901-12-13 20:45:52 through 2038-01-19 03:14:07 UT" and are present only for old readers.
- Version 2+ header and data block. The same data again with 64 bit times, which "can represent times approximately 292 billion years into the past or future."
- Footer. A newline delimited POSIX style TZ string, such as
EST5EDT,M3.2.0,M11.1.0, that tells readers how to compute transitions after the last one stored explicitly. Version 3 allows an extension to that string; version 4 adds rules about leap second tables.
The 2038 boundary is the limit covered in Y2K, Y2038 and the next time bug; leap second handling, which TZif can also carry, is covered in the leap second bug.
The footer matters for this year's Canadian changes. When a zone moves to a fixed offset, its footer becomes a simple string with no DST part. A reader that relies on an old file sees the old footer, which still says "fall back in November."
Linux and macOS: /usr/share/zoneinfo and /etc/localtime
On Linux and macOS the compiled files live in a tree such as /usr/share/zoneinfo, one file per zone name (/usr/share/zoneinfo/America/New_York). The tzfile(5) page says the files "are typically found under a directory with a name like /usr/share/zoneinfo." The system default zone is usually /etc/localtime, a symbolic link to one of those files or a copy of it. The TZ environment variable overrides it per process; the tz-link page notes that on a POSIX.1-2024 system you set TZ="America/New_York".
Two details catch operators. If /etc/localtime is a copy rather than a link, a tzdata package update does not change it. And long running processes typically read the zone file once, so they may keep old rules until restarted.
Windows: registry time zones and CLDR mapping
Windows does not use IANA names for its system time zones. The tz-link page describes "the older, proprietary method of Microsoft Windows 2000 and later, which stores time zone data in the Windows Registry," with IDs such as "Pacific Standard Time" rather than America/Los_Angeles. It also notes that Windows 8.1 and later carry tz data and CLDR data used by Windows Runtime classes such as DateTimeFormatter and Calendar.
Microsoft's daylight saving time support policy says it monitors announced changes and ships them through Windows Update, each update superseding earlier ones; when there is "insufficient lead time," it publishes "interim guidance on the DST Blog." To translate between Windows IDs and IANA names, use the Unicode CLDR windowsZones.xml mapping rather than a hand written list.
How do runtimes carry their own copy?
This is the part that surprises people. Updating the operating system's tzdata package fixes programs that read /usr/share/zoneinfo through the C library. It does nothing for a runtime that ships its own copy, and many do.
Java
Java does not read the OS zoneinfo files. The tz-link page notes that Oracle Java "contains a copy of a subset of a recent tz database in a Java-specific format" inside the runtime. Oracle's TZUpdater documentation recommends the latest JDK or JRE update release "as the preferred means" of getting new data. When that is not possible, TZUpdater patches one installed runtime per run, and you "must stop any running instances" of it first. java -jar tzupdater.jar -V prints the tzdata version in the runtime and the version the tool would install; -l compiles and installs a tzdata tarball, by default the latest IANA release, with SHA-512 checks on the download.
Every JDK in a container image, every JRE bundled in a desktop app and every application server with its own runtime is a separate copy.
ICU, and therefore Node.js and browsers
ICU (International Components for Unicode) is the library behind Intl.DateTimeFormat in many JavaScript engines and platforms. The ICU time zone guide says "ICU derives its tz data from the IANA Time Zone Database" and that the project publishes updated resource files after IANA releases: zoneinfo64.res, windowsZones.res, timezoneTypes.res and metaZones.res. You replace them in a .dat package with icupkg, rebuild a shared data library, or, for ICU4C 54 and newer, drop them in a directory named by the ICU_TIMEZONE_FILES_DIR environment variable, which ICU checks first.
Node.js builds with full-icu by default, per its internationalization docs, embedding ICU data in the binary, and process.versions includes a tz field that reports the tz version it carries. The Node binary in an image therefore has time zone data separate from both the OS and any browser. Browsers update their own copy with browser releases, and there is no standard API that returns the tzdata version from inside a web page.
Python
Python 3.9 added the standard library zoneinfo module. It reads TZif files from the directories in zoneinfo.TZPATH (normally the OS zoneinfo tree) and, if no system data is found, falls back to "the first-party tzdata package available on PyPI," which is "maintained by the CPython core developers." Some platforms, Windows in particular, have no system tz files, so code that runs there depends on the tzdata package being installed.
The tzdata package on PyPI uses its own version scheme. The latest release at the time of writing is 2026.5, uploaded on 3 October 2026. A Python service can therefore get its rules from the OS files, a pinned tzdata wheel or a third party library with data of its own, depending on which copy wins.
Go
Go's time.LoadLocation looks for the database in a fixed order, per the time package docs: the directory or zip named by the ZONEINFO environment variable on Unix, the system's standard installation location, $GOROOT/lib/time/zoneinfo.zip, and finally the time/tzdata package if the program imported it. The time/tzdata docs say importing it embeds "a copy of the timezone database," adds "about 450 KB" to the binary, and happens automatically when you build with -tags timetzdata.
That embedded copy is frozen at the toolchain that built the binary, so a static Go binary in a scratch image keeps its build date rules until rebuilt. Without embedded data or zoneinfo files in the image, LoadLocation fails.
JavaScript libraries in your bundle
moment-timezone (latest 0.6.5 on the npm registry, described as "Parse and display moments in any timezone") ships its own packed copy of the tz data, which ends up inside your bundle and changes only when you upgrade the package. date-fns-tz (latest 3.2.0), by contrast, describes itself as "Time zone support for date-fns v3 with the Intl API," which means it relies on the runtime's ICU data. One is a dependency you must bump; the other inherits the runtime's data.
Android and Apple platforms
Android has moved time zone updates out of the system image. The Android time zone rules page says Android 10 replaced the older APK based update mechanism with "an APEX-based module update mechanism" (the Time Zone Mainline module), and the APK route "has been completely removed from Android 14 onwards." OEMs still control testing and timing. An app that bundles its own time library with embedded data does not benefit from module updates.
The tz-link page lists iOS and macOS among systems that use tz data. We found no separate Apple time zone update channel documented, so plan on fixes arriving with OS updates and test on devices that have not updated.
Why one host can disagree with itself
Put those together on one Linux server running a container with a Java service, a Node sidecar and a Python job:
| Process | Where its tz data comes from |
|---|---|
date in a shell | The image's /usr/share/zoneinfo, from the base image's tzdata package |
| The Java service | The tz copy inside the JDK in the image |
| The Node sidecar | ICU data compiled into the Node binary |
| The Python job | OS files via TZPATH, or the tzdata wheel if the image has none |
| The host's own logs | The host's /usr/share/zoneinfo, updated by the host's package manager |
On 2 November 2026 those five could show different local times for Edmonton if even one predates 2026c. Nothing crashes; the data is just old.
Platform comparison: where tz data comes from and how to check it
| Platform or runtime | Source of tz data | How it is updated | How to check the version |
|---|---|---|---|
| Debian and Ubuntu | tzdata package, files in /usr/share/zoneinfo | apt package updates | dpkg -s tzdata (Version line) |
| RHEL, Fedora and derivatives | tzdata package | dnf or yum updates | rpm -q tzdata |
| Alpine | tzdata package (not always in base images) | apk updates | apk info -v tzdata |
| macOS | System zoneinfo tree | macOS updates | ls -l /etc/localtime; zdump on a known transition |
| Windows | Registry time zones, plus tz and CLDR data for some APIs | Windows Update; interim guidance on Microsoft's DST blog | Windows Update history |
| Java | Java specific data inside each JDK or JRE | JDK update release, or TZUpdater | java -jar tzupdater.jar -V |
| Node.js | ICU data in the binary (full-icu by default) | New Node release, or system ICU | node -p process.versions.tz |
| Browsers | ICU or equivalent inside the browser | Browser updates | Browser version; test a known transition |
| Python | OS files via zoneinfo.TZPATH, else the tzdata PyPI package | OS updates, or pip upgrade of tzdata | python3 -c "import zoneinfo; print(zoneinfo.TZPATH)"; pip show tzdata |
| Go | ZONEINFO, system files, $GOROOT/lib/time/zoneinfo.zip, or embedded time/tzdata | System updates, or rebuild with a newer toolchain | go version of the build; check whether the binary embeds time/tzdata |
| ICU4C apps | zoneinfo64.res and related resources | Drop in .res files, icupkg, or rebuild | The ICU version and the .res files in use |
| Android | Time Zone Mainline module (Android 10 and later) | Module updates via the platform, or OS updates | Device settings and OS update level |
| iOS | System data | iOS updates | iOS version |
npm with bundled data (for example moment-timezone) | Data packed in the library | Upgrade the package | npm ls moment-timezone |
What breaks on the change?
Most time zone bugs come from treating local time as a continuous, unique timeline. It is neither.
Ambiguous times in autumn
When clocks fall back, an hour of local time happens twice. In New York on 1 November 2026, 01:30 occurs first at minus 4 (EDT) and then an hour later at minus 5 (EST). A timestamp written as 2026-11-01 01:30 with no offset is ambiguous: it could be either of two instants an hour apart.
Python models this with the fold attribute, which the zoneinfo docs describe as choosing the offset "from before the transition" when fold=0 and "after the transition" when fold=1:
from datetime import datetime
from zoneinfo import ZoneInfo
ny = ZoneInfo("America/New_York")
first = datetime(2026, 11, 1, 1, 30, tzinfo=ny)
second = first.replace(fold=1)
print(first.isoformat()) # 2026-11-01T01:30:00-04:00
print(second.isoformat()) # 2026-11-01T01:30:00-05:00
Java's ZonedDateTime makes the same choice explicit with withEarlierOffsetAtOverlap() and withLaterOffsetAtOverlap(). Whatever language you use, decide which instant you mean and record the offset.
Non-existent times in spring
When clocks spring forward, an hour of local time never happens. In New York on 8 March 2026, the clock went from 01:59:59 to 03:00:00, so 02:30 did not exist. Libraries differ in what they do with a non-existent time: some shift it forward, some raise an error, some silently attach the pre-transition offset. A job scheduled "every day at 02:30 local" either runs at a surprising time or not at all that day. Our scheduled tasks post covers the scheduling side in detail.
Logs that sort wrongly
If logs record local time without an offset, the repeated autumn hour produces lines that look out of order: 01:59 EDT is followed by 01:00 EST, which sorts earlier. During an incident, that is an hour in which you cannot trust the sequence of events.
Billing, rate windows and reports
Daily billing cutoffs, quotas that reset "at midnight" and reports grouped by local day assume a 24 hour day. In zones with DST, one day a year has 23 hours and one has 25, so charges computed from local wall clock differences can be off by an hour. Our post on exception expiry timestamps and end of day rules works through one variant of this problem in a security tool.
Expiry checks written in local time
Certificates, signed URLs and tokens carry expiry times in UTC or Unix seconds. Code that compares them to a local "now" with a wrong offset, for example from stale tz data, can accept a token an hour too long or reject one an hour early. Compare instants, not wall clock readings.
Stale data in a zone that stopped changing
This year adds a pattern that most teams have not seen before. On 1 November 2026, a server in Calgary with tzdata older than 2026c will move its local clock from minus 6 to minus 7. Anything that displays local time, schedules local jobs or computes local days from that server will be an hour off from then on, with no error and no alert. The same applies to Vancouver (2026b), Inuvik (2026d) and Winnipeg (2026e). Morocco's change to permanent plus 00 on 20 September 2026 (2026c) is already in effect for Africa/Casablanca, so data older than 2026c is already wrong there.
Step by step: make your systems time zone safe
1. Store and log in UTC with an explicit offset
RFC 3339 defines the timestamp profile most APIs use: 2026-11-01T06:30:00Z or 2026-11-01T01:30:00-05:00. It is blunt about the alternative: because interpreting an unqualified local time "will fail in approximately 23/24 of the globe," unqualified local time is "deemed unacceptable for the Internet." It also defines -00:00 for the case where the UTC time is known but the local offset is not.
In practice:
- Store instants as UTC (or Unix time) in databases, queues and logs.
- When a local wall time matters to the business (an appointment at 09:00 in Toronto), store the wall time and the IANA zone name, not a fixed offset. Offsets change;
America/Torontofollows the law. - Configure log formatters to emit UTC with a
Zsuffix, or at least an explicit numeric offset. - Convert to local time only at the edge, when you show a time to a person or accept one, using their IANA zone name. Never pass local times without offsets between services.
2. Run servers in UTC
Set hosts and containers to UTC unless a legacy dependency forbids it. On systemd hosts:
timedatectl # shows the current zone and NTP status
sudo timedatectl set-timezone UTC
ls -l /etc/localtime # should point into the zoneinfo tree
For containers, set TZ=UTC in the image or the deployment. A server in UTC has no DST transitions of its own, which removes a whole class of scheduling surprises. It does not remove the need for current tz data, because your application still converts for users in other zones.
3. Find every copy of tz data on hosts and images
Check the OS package first:
# Debian and Ubuntu
dpkg -s tzdata | grep '^Version'
# RHEL, Fedora and derivatives
rpm -q tzdata
# Alpine
apk info -v tzdata
# Any system with the zoneinfo tree and zdump: what will happen on 1 Nov 2026?
zdump -v -c 2026,2027 America/Vancouver America/Edmonton America/Winnipeg America/New_York
zdump -v prints every transition in the range with its offset and isdst flag. With current data, America/New_York shows a transition on 1 November 2026, while America/Vancouver, America/Edmonton and America/Winnipeg show the change to their permanent standard abbreviation with no change in UT offset. If those three show an offset change on 1 November, the host's data is stale.
Then check each runtime:
# Java: tzdata version inside the runtime that runs the tool
java -jar tzupdater.jar -V
# Node.js: tz version compiled into the binary
node -p process.versions.tz
# Python: where zoneinfo looks, and the tzdata wheel if installed
python3 -c "import zoneinfo; print(zoneinfo.TZPATH)"
pip show tzdata
# npm: libraries that bundle tz data
npm ls moment-timezone
For Go, check whether the binary embeds time/tzdata (an import in main or the timetzdata build tag) and which toolchain built it; if it does not embed data, check that the image contains a zoneinfo tree or sets ZONEINFO.
4. Use your SBOM to find copies you forgot
Most of the copies above are ordinary components in a software bill of materials: the tzdata OS package in a container image, the JDK or JRE, the Node runtime, the Python tzdata wheel and npm packages such as moment-timezone. Generate an SBOM for each image and repository, then search it:
# Example with the Safeguard CLI: scan an image, write results to out/
safeguard scan --image registry.example.com/billing-api:2026-10-20 --output out/
grep -ril 'tzdata\|moment-timezone\|openjdk\|icu' out/
Any SBOM tool that lists OS packages and language dependencies will do the same job. What you want is a list of every image and app that carries a tz data copy, with the version, so you can see which ones predate 2026e. Vulnerability scanners will not flag stale tzdata on their own, because a rule change is not a CVE. This is an inventory question, and inventory is what an SBOM is for.
5. Update, rebuild and restart
- Hosts: install the latest tzdata package and restart services that read zone files at startup.
- Container images: rebuild from an updated base image and redeploy; check that
/etc/localtimeis a link, not a copy. - Java: take the latest JDK update release, or run TZUpdater against each runtime with the JVMs stopped.
- Node.js and Go: move to a Node release with a current
process.versions.tz; rebuild Go binaries that embedtime/tzdatawith a current toolchain. - Python: upgrade and pin the
tzdatawheel in every environment that depends on it. - Mobile: ship app updates for libraries that bundle data, and test on devices without the latest OS or module update.
6. Test against fixture dates on both change nights
Write tests that pin the dates that matter and assert offsets, not just formatted strings. A canary test for this autumn:
from datetime import datetime, timedelta
from zoneinfo import ZoneInfo
def test_zones_after_1_nov_2026():
cases = {
"America/New_York": -5, # falls back on 1 Nov 2026
"America/Vancouver": -7, # permanent -07 (tzdata 2026b or later)
"America/Edmonton": -6, # permanent -06 (2026c or later)
"America/Winnipeg": -5, # permanent -05 (2026e or later)
"Europe/London": 0, # fell back on 25 Oct 2026
}
for zone, hours in cases.items():
t = datetime(2026, 11, 2, 12, 0, tzinfo=ZoneInfo(zone))
assert t.utcoffset() == timedelta(hours=hours), zone
Run the same assertions in every runtime you ship, on the images you ship, in CI. Add a spring fixture (8 March 2026 at 02:30 in New York) and an autumn fixture (1 November 2026 at 01:30) to tests for any code that schedules, bills or expires things in local time. Because this test reads whichever data the runtime finds first, it doubles as a check that a stale copy has not crept in.
7. Subscribe to tz-announce
Subscribe a shared team mailbox to tz-announce@iana.org, and when a release lands, compare its "Briefly" summary in the NEWS file against the zones your users live in.
The supply chain angle: tzdata is a dependency
Time zone data feels like part of the operating system. Treat it instead as a third party dependency, because that is what it is: an upstream project with its own release cadence, repackaged by distributions, runtimes and libraries, and copied into your artifacts at build time. That changes a few habits:
- Inventory it. Each copy has a version you can query. An SBOM per image and per app makes the list complete instead of a guess.
- Pin and update deliberately. Pin the
tzdatawheel, the npm library and the base image digest, and update them on purpose when a release matters, rather than hoping a rebuild picks it up. - Watch for frozen copies. Images built months ago and never rebuilt, Go binaries with embedded data, desktop apps with a bundled JRE and mobile apps with bundled libraries all freeze tz data at their build date.
A month between a release and a legal change leaves little room for every link in that chain, and the last link is your build.
Common mistakes
- Scheduling in local time on servers. A job at "02:30 local" skips a day in spring and may run twice in autumn. Schedule in UTC, or use a scheduler that understands zone transitions and test it on both nights.
- Assuming every zone changes on the same date. Europe changed on 25 October 2026 at 01:00 UTC; the US changes on 1 November at 02:00 local; much of the world does not observe DST; and this year parts of Canada stop changing altogether. There are weeks each spring and autumn when the gap between New York and London is four hours instead of five.
- Hard coding offsets. Storing "minus 8" for Vancouver was wrong from 9 March 2026 onward. Store
America/Vancouverand let current data compute the offset. - Trusting the base image's tzdata. A base image tag can be months old, and some minimal images have no zoneinfo tree at all. Check the package version and the build date.
- Updating the OS and forgetting the runtimes. A new tzdata package does nothing for Java, Node's built in ICU, Go's embedded data or a library in your JavaScript bundle.
- Not restarting, or copying /etc/localtime. Processes that loaded zone data at startup keep old rules until restarted, and a copied
/etc/localtimenever updates. Use a link. - Using abbreviations as identifiers. "CST" means different things in different places, and in Alberta it now names a permanent offset. Use IANA names.
FAQ
What is the IANA time zone database?
It is a public, volunteer maintained set of text files and reference code that records the history and current rules of local time for locations worldwide since 1970. IANA hosts it, a TZ Coordinator manages releases under RFC 6557, and almost every operating system and major runtime derives its time zone data from it.
Who updates the tz database when a country changes its clocks?
Anyone can report a change to the public tz@iana.org mailing list, ideally with a link to the official law or regulation. The TZ Coordinator decides what goes into the data, in consultation with the list, and publishes a release. RFC 6557 says the coordinator does not set time zone policy; the data follows what governments decide and what people on the ground actually do.
What does a tzdata version like 2026e mean?
It is the year followed by a letter that increments with each release in that year: 2026a was the first release of 2026 and 2026e the fifth. Since 2016h each release includes a version file containing that string, and many runtimes report it, for example Node's process.versions.tz.
How do I check which tzdata version my server uses?
Query the OS package (dpkg -s tzdata, rpm -q tzdata or apk info -v tzdata) and run zdump -v -c 2026,2027 on a recently changed zone. Then check each runtime separately, since Java, Node.js, Python and Go can each carry their own copy.
When did clocks change in the UK and Europe in 2026, and when does the US change?
The EU rule in the tz data, which the UK also follows, falls back on the last Sunday of October at 01:00 UTC, which was 25 October 2026. US daylight saving time ends at 2 a.m. local time on the first Sunday of November under 15 U.S.C. 260a, which is 1 November 2026, as NIST also states.
Why will some Canadian clocks not fall back on 1 November 2026?
British Columbia, Alberta, the Northwest Territories and Manitoba each moved to a permanent standard offset during 2026, recorded in tzdata releases 2026b, 2026c, 2026d and 2026e. Devices with current data will keep their clocks where they are on 1 November. Devices with older data will move back an hour, which would be wrong.
Does Windows use the IANA time zone database?
Windows system time zones use their own registry based IDs such as "Pacific Standard Time" and are updated through Windows Update. Windows 8.1 and later also carry tz and CLDR data for some Windows Runtime APIs. To map between Windows IDs and IANA names, use the CLDR windowsZones.xml table.
Is updating the tzdata package enough?
No. It fixes software that reads the OS zoneinfo files. Java, Node.js, browsers, Python's tzdata wheel, Go binaries with embedded data and libraries such as moment-timezone carry their own copies, and long running processes may need a restart.
Where Safeguard fits
Safeguard does not maintain time zone data, update operating systems or fix clock handling in your code for you. Its fit here is the inventory problem. Safeguard scans repositories, container images and SBOM files (safeguard scan --dir ., --image or --sbom) and lists the components and versions inside, so a tzdata OS package, a JDK, a Node runtime, a Python tzdata wheel or an npm library such as moment-timezone shows up wherever your SBOM records it. The platform shows which projects contain a given component and version, so after a tz release you can ask which images and apps still carry an older copy and rebuild them. A stale time zone rule is not a vulnerability, so it will not appear as a CVE finding; treat it as a version check across your inventory.
Time zone data is a small, quiet dependency, and the habits that keep it current (knowing what you ship and rebuilding when upstream releases) are the same ones that close security gaps in every other open source component in your images. The steps below are how Safeguard helps with the security side of that inventory.
Fix it without waiting for upstream
Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.
1. Autonomous remediation: pull requests, not tickets
When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation categories include dependencies, licenses, security posture and findings, and each one is set separately. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.
2. Gold Open Source: the safe version in seconds, free
gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds.
3. Gold Registry: start from components that are already fixed
Gold Registry provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs and a completed license check, with signed build provenance (signed with Safeguard's key and verifiable with cosign, SLSA Build Level 3 as the design target) and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.
When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. Ask which packages it covers before you plan around it.
| Your situation | What to use |
|---|---|
| A fixed version exists | Autonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version |
| You need to know today whether you are affected | Gold Open Source lookup and "Am I affected?" checker, free and without login |
| You want vulnerable versions to stop shipping | Safeguard policies and gates in CI |
| Upstream has no fix yet, or will not ship one | A custom Gold request; fork and patch |
| You want to start clean on new projects | Pull hardened components and images from Gold Registry |
One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.
See how Safeguard would help
These demos show dependency scanning and remediation, not clock or scheduler fixes. You can download Safeguard and follow the CLI docs to try them on your own projects.
This demo sets up the Safeguard runner on your own machine, approves it with its device code and scans from the terminal. Pointed at a container image, the same scan lists the OS packages and runtimes inside, including any tzdata package and the JDK or Node version, so you can see which images need a rebuild after a tz release.
Click through it at your own pace, or open it full screen.
This demo is a real CLI session: asked to fix the lodash CVE in a repository, it reads the finding and the advisory, edits package.json to lodash 4.17.21 and runs npm install and npm test, asking before any command that changes something and pushing nothing. The same flow applies when you need to bump a time zone library such as moment-timezone or a pinned Python tzdata wheel and run your fixture date tests before merging.
Click through it at your own pace, or open it full screen.
This demo connects Claude to the Safeguard MCP server with OAuth and lets you choose which tools Claude can use. You can then ask which of your projects ship a given component version, such as an older tzdata package or JDK, and get the answer from your own scan data.
Click through it at your own pace, or open it full screen.
Quick check
A server's tzdata package is current, but a Java service on it shows the wrong local time for Edmonton after 1 November 2026. Why?
Java does not read the OS zoneinfo files. It uses its own copy inside the JDK, which must be updated through a newer JDK update release or the TZUpdater tool, with the JVM stopped. Alberta's permanent minus 06 is in tzdata 2026c and later.
Why is "2026-11-01 01:30" in New York not a safe value to store?
That local time happens twice on 1 November 2026, first at minus 4 and then at minus 5, so it names two different instants an hour apart. Store the UTC instant, or the local time with an explicit offset as RFC 3339 allows.
Sources
- IANA: Time Zone Database
- tz database NEWS file (release notes, 2026a to 2026e)
- Sources for time zone and daylight saving time data (tz-link)
- Theory and pragmatics of the tz code and data
- tz source file: europe (eggert/tz repository)
- tz source file: northamerica (eggert/tz repository)
- tz source file: etcetera (eggert/tz repository)
- tz-announce mailing list archive
- RFC 6557: Procedures for Maintaining the Time Zone Database
- RFC 9636: The Time Zone Information Format (TZif)
- RFC 3339: Date and Time on the Internet: Timestamps
- tzfile(5) Linux manual page
- 15 U.S.C. 260a: Advancement of time or changeover dates
- NIST: Daylight Saving Time (DST)
- Oracle: Timezone Updater Tool (TZUpdater) README
- Python docs: zoneinfo
- PyPI: tzdata
- ICU User Guide: Time Zones
- Node.js docs: Internationalization support
- Node.js docs: process.versions
- Go: package time
- Go: package time/tzdata
- Android Open Source Project: Time zone rules
- Microsoft: Daylight saving time help and support
- Unicode CLDR: windowsZones.xml
- npm registry: moment-timezone
- npm registry: date-fns-tz
Last reviewed: 26 October 2026. Time zone rules can change with little notice, and a new tz release may follow 2026e (the unreleased development notes say regulation now lets northwestern Ontario follow Manitoba, which would avoid a data change); check the IANA page for the latest version before relying on a date in this post.