Some topics in computer science fascinate me, and time handling is one of them. At first it sounds simple, but there are a lot of edge cases behind it, and it’s tied to politics and to people’s everyday lives.
On November 1st 2026, at 2:00 in the morning, while most of North America is asleep, the clocks will fall back one hour. Not in British Columbia, Alberta, the Northwest Territories and Manitoba. They have all decided to stay on “permanent daylight time”, and they all announced it in 2026, joining Yukon and most of Saskatchewan, which already don’t change their clocks. The last one, Manitoba, announced it just six weeks before the change.
If your servers, containers or databases do not have the latest version of the time zone database, every timestamp they display for several Canadian provinces after November 1st will be one hour off. And worse: today, even the latest versions of popular Docker images are out of date.
Context
Daylight saving time in Canada is decided by each province, not by the federal government. For years, several provinces and territories have passed laws to stop changing the clocks, British Columbia in 2019, Northwest Territories in 2021, Manitoba in 2023, but kept them on hold, waiting for their neighbours to do the same. Nobody wanted to be the only one an hour off from their main trading partner, so nothing happened.
In 2026 it all moved very quickly:
- British Columbia went first, in March, without waiting for Washington state and California.
- Alberta followed in April, staying one hour ahead of British Columbia all year long and joining Saskatchewan, which has been on UTC-6 all year for decades.
- Northwest Territories followed Alberta.
- Manitoba ran a public survey and finally chose to stay on daylight time too.
- Some small communities in the south-east of British Columbia (East Kootenay, Golden), which historically follow Alberta time, had to decide which neighbour to follow. Some of them changed their mind along the way.
For a human it’s simple: “don’t touch the clock on November 1st”. For a computer it’s another story. Computers don’t know anything about politics: they use the IANA time zone database (tzdata, or “Olson database”) to convert a UTC timestamp to a local time. When a government changes the rules, the database must be updated by its volunteer maintainers, released, then packaged by every Linux distribution, every language runtime and every database that ships its own copy, and finally installed on your machines.
If at any point in this chain an update is missing, your system will happily fall back one hour on November 1st for America/Vancouver, America/Edmonton or America/Winnipeg.
If you want to understand what’s happening, the NEWS file of the time zone database is a precious source. Each release explains which governments changed what and how the maintainers chose to model it, and the data files themselves cite the laws and announcements. All the tzdata dates of this article come from there.
The timeline of decisions and tzdata releases
| Date | Event |
|---|---|
| 2026-03-01 | tzdata 2026a released (nothing about Canada) |
| 2026-03-02 | British Columbia announces that the March 8 spring forward will be the last clock change |
| 2026-03-08 | Last spring forward in British Columbia, Alberta and Manitoba |
| 2026-03-09 | British Columbia law in force: Pacific Time is now UTC-7 all year |
| 2026-04-20 | Alberta announces permanent daylight time, Northwest Territories announces it will follow |
| 2026-04-22 | tzdata 2026b: America/Vancouver stays on UTC-7 |
| 2026-05-14 | Bill 31 receives Royal Assent |
| 2026-06-18 | Alberta Official Time Act in force (Order in Council 204/2026): “Alberta Time” is UTC-6 all year |
| 2026-07-08 | tzdata 2026c: America/Edmonton stays on UTC-6 |
| 2026-08-21 | Northwest Territories regulation in force |
| 2026-09-11 | tzdata 2026d: America/Inuvik stays on UTC-6 |
| 2026-09-17 | Manitoba announces permanent daylight time |
| 2026-09-23 | Manitoba Order in Council 221/2026: the change is legally in force on October 31st |
| 2026-09-29 | tzdata 2026e: America/Winnipeg stays on UTC-5 |
| 2026-11-01 | The day the clocks would have fallen back |
The tz maintainers have been very reactive: 12 days between the Manitoba announcement and the release of 2026e, while the official Order in Council was only signed 6 days before the release. For British Columbia it took longer (51 days), but there was no urgency: the first visible difference is on November 1st.
Vancouver
British Columbia’s law came into force on March 9th, and tzdata 2026b was released 6 weeks later. The first visible difference is on November 1st: 8 months after the announcement. That’s the comfortable case.
Edmonton
Alberta’s Official Time Act came into force on June 18th, and tzdata 2026c was released 3 weeks later. Still almost 4 months of margin before November 1st.
Winnipeg
Manitoba is the problematic one. The survey results and the decision were published on September 17th, just over six weeks before the clocks would fall back. The law itself already existed since 2023: it only needed to be proclaimed, which was decided on September 23rd with an effective date of October 31st, 26 hours before the fall back.
tzdata 2026e was released on September 29th, leaving 33 days for the update to reach every system before November 1st.
The timeline in Ubuntu
Now the interesting part: how long does it take for this data to reach a real server? I used the Launchpad API to get the publishing history of the tzdata package.
On Ubuntu, a stable release update (SRU) first goes to the -proposed pocket, where it’s tested, then it’s copied to -updates and -security. Only -updates and -security are enabled by default.
| tzdata | IANA release | Ubuntu 26.10 (dev) | Stable -proposed |
Stable -updates |
|---|---|---|---|---|
| 2026b (Vancouver) | 2026-04-22 | 2026-06-16 | 2026-06-24 | 2026-07-08 |
| 2026c (Edmonton) | 2026-07-08 | 2026-07-30 | 2026-07-17 | 2026-07-29 |
| 2026d (Inuvik) | 2026-09-11 | skipped | skipped | skipped |
| 2026e (Winnipeg) | 2026-09-29 | 2026-10-04 | 2026-10-05 | not yet |
Stable releases are 22.04 LTS (Jammy), 24.04 LTS (Noble) and 26.04 LTS (Resolute).
Some observations:
- For British Columbia, it took 128 days between the government announcement and the update reaching Ubuntu users, and 77 days between the IANA release and the Ubuntu update. There was no urgency: the change was only visible in November.
- For Alberta, Ubuntu was faster: 21 days between the IANA release and
-updates. - 2026d was skipped and Ubuntu went directly to 2026e. It’s fine since 2026e contains all previous changes.
- For 2026e, Ubuntu reacted quickly: 6 days between the IANA release and
-proposed. - At the time of writing (October 10th), 2026e is still in
-proposedfor all stable releases. If it follows the same path as 2026c, it should reach-updatesaround mid-October. That leaves two weeks for every server, every Docker image and every appliance to be updated.
You can check what you have with:
apt-cache policy tzdata
And the easiest test, which doesn’t depend on any language:
TZ=America/Winnipeg date -d '2026-11-15 12:00 UTC'
It must display 07:00, not 06:00.
What about Docker images?
Most applications don’t run directly on the host anymore. Each Docker image has its own copy of tzdata (or none at all), coming from its base distribution, or sometimes bundled in the application itself. I pulled the latest version of some popular images on October 10th and tested them.
The test is always the same: convert 2026-11-15 12:00 UTC to local time. The correct answer is:
| Zone | Correct | Old rules |
|---|---|---|
| America/Vancouver | 05:00 (UTC-7) | 04:00 (UTC-8) |
| America/Edmonton | 06:00 (UTC-6) | 05:00 (UTC-7) |
| America/Winnipeg | 07:00 (UTC-5) | 06:00 (UTC-6) |
Python
python:latest is Python 3.14.8 on Debian 13 (Trixie).
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
utc = datetime(2026, 11, 15, 12, 0, tzinfo=timezone.utc)
for tz in ("America/Vancouver", "America/Edmonton", "America/Winnipeg"):
print(f"{tz:20} {utc.astimezone(ZoneInfo(tz)).isoformat()}")
America/Vancouver 2026-11-15T05:00:00-07:00
America/Edmonton 2026-11-15T06:00:00-06:00
America/Winnipeg 2026-11-15T06:00:00-06:00
Winnipeg is wrong. zoneinfo uses the system time zone files first, and Debian Trixie ships tzdata 2026c-0+deb13u1. At the time of writing, 2026e is only available in Debian unstable (sid) and testing (forky).
Python has a nice escape hatch: the tzdata package on PyPI, which is updated very quickly (2026.5, containing 2026e, was released on October 3rd). But zoneinfo only uses it as a fallback if the system files are missing. You can force it by emptying the search path with the PYTHONTZPATH environment variable:
pip install tzdata
PYTHONTZPATH= python test.py
America/Winnipeg 2026-11-15T07:00:00-05:00
Be careful, if you use pytz instead of zoneinfo, it ships its own copy of the database, and you need to upgrade it as well.
Ruby
ruby:latest is Ruby 4.0.7 on the same Debian Trixie base.
Ruby’s Time doesn’t have a native time zone database, it relies on the libc via the TZ environment variable:
t = Time.utc(2026, 11, 15, 12, 0)
%w[America/Vancouver America/Edmonton America/Winnipeg].each do |tz|
ENV["TZ"] = tz
puts "#{tz.ljust(20)} #{t.dup.localtime.strftime("%FT%T%:z")}"
end
America/Vancouver 2026-11-15T05:00:00-07:00
America/Edmonton 2026-11-15T06:00:00-06:00
America/Winnipeg 2026-11-15T06:00:00-06:00
Same result as Python: Winnipeg is wrong.
Most Ruby applications (and all Rails applications through ActiveSupport::TimeZone) use the tzinfo gem. By default it reads the system files, unless the tzinfo-data gem is installed:
require "tzinfo"
t = Time.utc(2026, 11, 15, 12, 0)
%w[America/Vancouver America/Edmonton America/Winnipeg].each do |tz|
puts "#{tz.ljust(20)} #{TZInfo::Timezone.get(tz).to_local(t).strftime("%FT%T%:z")}"
end
puts TZInfo::DataSource.get
With tzinfo-data 1.2026.5:
America/Vancouver 2026-11-15T05:00:00-07:00
America/Edmonton 2026-11-15T06:00:00-06:00
America/Winnipeg 2026-11-15T07:00:00-05:00
Ruby DataSource: tzdb v2026e, tzinfo-data v1.2026.5
So bundle add tzinfo-data and you are good, as long as you don’t forget to bundle update tzinfo-data the next time.
PostgreSQL
postgres:latest is PostgreSQL 18.6, also on Debian Trixie.
PostgreSQL can ship its own copy of tzdata, but the Debian packages are built with --with-system-tzdata=/usr/share/zoneinfo, so it uses the system files.
SET TIME ZONE 'UTC';
SELECT tz, timestamptz '2026-11-15 12:00:00+00' AT TIME ZONE tz
FROM unnest(ARRAY['America/Vancouver', 'America/Edmonton', 'America/Winnipeg']) AS tz;
America/Vancouver|2026-11-15 05:00:00
America/Edmonton|2026-11-15 06:00:00
America/Winnipeg|2026-11-15 06:00:00
Winnipeg is wrong again. The simplest fix is to wait for the Debian update and rebuild the image.
Remember that PostgreSQL loads time zone data when a session uses it, so restart the server (or at least reconnect) after updating the tzdata package on an existing installation.
ClickHouse
clickhouse/clickhouse-server:latest is ClickHouse 26.9.14.10. The image is based on Ubuntu 22.04, but this doesn’t matter: ClickHouse embeds its own copy of tzdata in the binary.
WITH toDateTime('2026-11-15 12:00:00', 'UTC') AS t
SELECT
toDateTime(t, 'America/Vancouver') AS vancouver,
toDateTime(t, 'America/Edmonton') AS edmonton,
toDateTime(t, 'America/Winnipeg') AS winnipeg
FORMAT Vertical
vancouver: 2026-11-15 05:00:00
edmonton: 2026-11-15 06:00:00
winnipeg: 2026-11-15 07:00:00
All correct! You can check the embedded version with:
SELECT * FROM system.build_options WHERE name = 'TZDATA_VERSION'
TZDATA_VERSION 2026e
The downside of this approach is that you can’t update tzdata without upgrading ClickHouse itself. Here the ClickHouse team has been fast, but if you are stuck on an older version, there is nothing you can do with the system packages.
Java
eclipse-temurin:latest is OpenJDK 25.0.4.1 (released on August 18th) on Ubuntu 26.04.
Java doesn’t read the system files at all: the JDK ships its own compiled copy of the database in $JAVA_HOME/lib/tzdb.dat, and it’s only updated with a new JDK release.
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.zone.ZoneRulesProvider;
public class Main {
public static void main(String[] args) {
Instant t = Instant.parse("2026-11-15T12:00:00Z");
for (String tz : new String[]{"America/Vancouver", "America/Edmonton", "America/Winnipeg"}) {
System.out.printf("%-20s %s%n", tz, t.atZone(ZoneId.of(tz)).format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX")));
}
System.out.println("tzdb " + ZoneRulesProvider.getVersions("UTC").lastEntry().getKey());
}
}
America/Vancouver 2026-11-15T05:00:00-07:00
America/Edmonton 2026-11-15T05:00:00-07:00
America/Winnipeg 2026-11-15T06:00:00-06:00
tzdb 2026b
This is the worst result of this post: the JDK contains tzdata 2026b, so only Vancouver is correct. Edmonton and Winnipeg are both wrong, while the Ubuntu base image has 2026c. Updating the tzdata package of the image changes nothing.
The next quarterly JDK updates are scheduled for October 20th, 12 days before the change, and you will need to rebuild and redeploy every Java application in time. This also applies to everything running on the JVM: Elasticsearch, Kafka, Keycloak… If you use the Oracle JDK and can’t wait, Oracle provides the TZUpdater tool to patch its tzdb.dat directly from an IANA release.
Node.js
node:latest is Node.js 26.11.1 on Debian Trixie.
Node doesn’t use the system files either: the Intl API and toLocaleString rely on ICU, which is bundled in the Node binary with its own copy of tzdata.
const t = new Date(Date.UTC(2026, 10, 15, 12, 0));
for (const tz of ["America/Vancouver", "America/Edmonton", "America/Winnipeg"]) {
console.log(tz.padEnd(20), t.toLocaleString("en-CA", { timeZone: tz, hour12: false }));
}
console.log("tz", process.versions.tz, "icu", process.versions.icu);
America/Vancouver 2026-11-15, 05:00:00
America/Edmonton 2026-11-15, 06:00:00
America/Winnipeg 2026-11-15, 07:00:00
tz 2026e icu 78.3
Good news: Node.js already has 2026e and all the times are correct. You can check the bundled version with process.versions.tz.
Go
golang:latest is Go 1.27.2 on Debian Trixie.
package main
import (
"fmt"
"time"
)
func main() {
t := time.Date(2026, 11, 15, 12, 0, 0, 0, time.UTC)
for _, tz := range []string{"America/Vancouver", "America/Edmonton", "America/Winnipeg"} {
loc, err := time.LoadLocation(tz)
if err != nil {
panic(err)
}
fmt.Printf("%-20s %s\n", tz, t.In(loc).Format(time.RFC3339))
}
}
America/Vancouver 2026-11-15T05:00:00-07:00
America/Edmonton 2026-11-15T06:00:00-06:00
America/Winnipeg 2026-11-15T06:00:00-06:00
Winnipeg is wrong. Go looks for the time zone data in this order:
- The directory or zip file pointed to by the
ZONEINFOenvironment variable - The system files in
/usr/share/zoneinfo(Debian 2026c here) - Go’s own copy:
$GOROOT/lib/time/zoneinfo.zip, or the copy embedded in the binary withimport _ "time/tzdata"or-tags timetzdata
Go’s own copy in Go 1.27.2 is also 2026c. This is the trap for Go applications: a static binary built with time/tzdata and shipped in a scratch or distroless image has no system files and uses the database embedded at compile time. It will stay wrong until it’s rebuilt with a newer Go release.
Summary
| Image | Version | tzdata used | Vancouver | Edmonton | Winnipeg |
|---|---|---|---|---|---|
| python:latest | 3.14.8 | Debian 2026c | ✅ | ✅ | ❌ |
python + tzdata PyPI |
3.14.8 | 2026e | ✅ | ✅ | ✅ |
| ruby:latest | 4.0.7 | Debian 2026c | ✅ | ✅ | ❌ |
ruby + tzinfo-data |
4.0.7 | 2026e | ✅ | ✅ | ✅ |
| postgres:latest | 18.6 | Debian 2026c | ✅ | ✅ | ❌ |
| clickhouse-server:latest | 26.9.14.10 | embedded 2026e | ✅ | ✅ | ✅ |
| eclipse-temurin:latest | 25.0.4.1 | JDK 2026b | ✅ | ❌ | ❌ |
| node:latest | 26.11.1 | ICU 2026e | ✅ | ✅ | ✅ |
| golang:latest | 1.27.2 | Debian / Go 2026c | ✅ | ✅ | ❌ |
Three weeks before the change, the official latest images of Python, Ruby, PostgreSQL and Go are wrong for Winnipeg, and Java is wrong for Edmonton too. And these are the latest images: if you pin a version, use an older base or haven’t rebuilt your images since the summer, Edmonton (and maybe Vancouver) are probably wrong too.
Updating is not enough
Even with an up-to-date tzdata, there is one more trap. If your application stores future events in UTC, the conversion was done with the rules known at that time. A meeting created in September for November 15th at 10:00 in Winnipeg was stored as 16:00 UTC, using the old UTC-6 offset. With the new rules, 16:00 UTC is 11:00 in Winnipeg: the meeting now shows up one hour late.
Updating tzdata doesn’t fix the data already stored. For future events, the safest option is to store the local time with the time zone name, and to convert to UTC only when you need it.
Historical changes
Some recent examples, with the time between the official decision (announcement or publication) and the change:
| Country | Year | Decision | Change | Notice |
|---|---|---|---|---|
| Morocco | 2018 | October 26 | October 28 | 2 days |
| Mexico (Chihuahua) | 2022 | October 28 | October 30 | 2 days |
| Lebanon (postponed, then reverted) | 2023 | March 23 | March 25 | 2 days |
| Samoa | 2021 | September 20 | September 26 | 6 days |
| Syria | 2022 | October 4 | October 28 | 3 weeks |
| Kazakhstan | 2024 | January 19 | March 1 | 6 weeks |
| Egypt | 2023 | March 1 | April 28 | 8 weeks |
Compared to that, Manitoba’s six weeks look almost comfortable.
What’s next
Western Canada is probably just the beginning: the same debate is happening around the world.
In the United States, the House of Representatives passed the Sunshine Protection Act on July 14th, 2026, by 308 votes to 117. It would make daylight saving time permanent, with an option for states to stay on standard time instead. The bill now waits for the Senate. If it passes, it will be the biggest tzdata change in years, with dozens of zones and different choices from one state to another.
It would also trigger a domino effect in eastern Canada. Ontario already passed a law in 2020 to stay on daylight time permanently, but only if Quebec and New York State do the same.
In Europe, the European Parliament voted to end the clock changes in 2019, but the member states never agreed on which time to keep. The last Council discussion was in December 2019, then COVID-19 put the debate on hold for years. Spain relaunched the topic in October 2025, and the European Commission put it back on its 2026 agenda. Even with a quick agreement, nothing is expected before 2027 or 2028.
Each of these decisions will affect far more people than Western Canada. The question is whether they will come with a year of notice, or six weeks.
Conclusion
I’m in favour of ending the clock changes, and I’m happy to see governments finally moving on it. But changing the time takes time.
The tz maintainers did an impressive job: 12 days from the Manitoba announcement to a release. But the database is only the first step in a long chain: distributions, language packages, databases, Docker images, and finally your own deployments. Six weeks is not enough for this chain, and we can’t expect every maintainer along the way to react within days.
The year 2000 bug was in the end a non-event because the industry spent years preparing for a change everybody could see coming decades in advance. Here, governments change the time of millions of people with a few weeks of notice. The consequences range from a phone alarm ringing an hour late to more serious issues when systems get out of sync.
The tz project recommends at least a year of notice. Ending the clock changes already takes years of political work. Once that work is done, adding one or two more years before the change takes effect costs almost nothing, and saves a lot of trouble.
In the meantime, start anticipating the US and EU moves in your technical design: know every copy of tzdata you ship, and store future events with their time zone. The question is not really if it’s going to happen, but when.