Summary
workerd's embedded tzdata is older than IANA 2026c, so Africa/Casablanca and Africa/El_Aaiun still resolve to UTC+01 for instants on or after 2026-09-20T01:00:00Z. The correct offset from that instant is UTC+00.
The transition is 14 days away. It is a permanent change to plain UTC, not a seasonal one, so every Worker that renders a wall-clock time for Morocco or Western Sahara will be an hour late from 2026-09-20 onward, indefinitely.
Why this is easy to miss
The failure is silent. Date instants stay correct — only the wall-clock label is wrong — so responses look plausible and nothing throws. In our case, maghrib for 18:34Z rendered as 19:34 local instead of 18:34.
It also does not reproduce under some local toolchains. Bun already carries 2026c, so our unit tests and validation harness passed while production was wrong.
Reproduction
import { Miniflare } from "miniflare";
const script = `
export default { async fetch() {
const fmt = (d, tz) => new Intl.DateTimeFormat("en-GB", {
timeZone: tz, timeZoneName: "longOffset"
}).formatToParts(new Date(d)).find(p => p.type === "timeZoneName").value;
return Response.json({
before_casablanca: fmt("2026-09-19T12:00:00Z", "Africa/Casablanca"),
after_casablanca: fmt("2026-09-25T12:00:00Z", "Africa/Casablanca"),
after_el_aaiun: fmt("2026-09-25T12:00:00Z", "Africa/El_Aaiun"),
});
}};`;
const mf = new Miniflare({ modules: true, script, compatibilityDate: "2026-08-01" });
console.log(await (await mf.dispatchFetch("http://x/")).json());
await mf.dispose();
Observed on workerd 1.20260906.1 (also on 1.20260730.1, and reported against production Workers on 2026-08-25):
{
"before_casablanca": "GMT+01:00",
"after_casablanca": "GMT+01:00",
"after_el_aaiun": "GMT+01:00"
}
Expected, per 2026c:
{
"before_casablanca": "GMT+01:00",
"after_casablanca": "GMT",
"after_el_aaiun": "GMT"
}
| Instant (UTC) |
workerd 1.20260906.1 |
Expected (2026c) |
| 2026-09-19T12:00:00Z |
+01:00 |
+01:00 |
| 2026-09-20T00:00:00Z |
+01:00 |
+01:00 |
| 2026-09-20T02:00:00Z |
+01:00 |
+00:00 |
| 2026-10-15T12:00:00Z |
+01:00 |
+00:00 |
| 2026-12-01T12:00:00Z |
+01:00 |
+00:00 |
Source for the rule
- IANA tzdb 2026c, from the
[PROPOSED] Morocco goes to plain UTC on 2026-09-20 thread on tz@iana.org (Paul Eggert, 2026-07-04).
- Morocco's National Telecommunications Regulatory Agency posted to the same list.
- Moroccan Decree 2.26.530.
Both Africa/Casablanca and Africa/El_Aaiun are covered by the decree, and both are affected here.
Impact
Anything that formats a Moroccan wall-clock time in a Worker: scheduling, calendar exports, business-hours logic, prayer times. Because Date instants remain correct, existing tests that compare instants will not catch it — only tests that assert on rendered local time will.
What we did meanwhile
We added a runtime-conditional override that formats Casablanca/El_Aaiun instants at or after 2026-09-20T01:00:00Z in UTC, but only while the runtime disagrees, so it disables itself once the embedded tzdata catches up. Happy to share that if useful, though the real fix is the tzdata bump.
Please let me know if a minimal repro repo would help.
Summary
workerd's embedded tzdata is older than IANA 2026c, soAfrica/CasablancaandAfrica/El_Aaiunstill resolve to UTC+01 for instants on or after 2026-09-20T01:00:00Z. The correct offset from that instant is UTC+00.The transition is 14 days away. It is a permanent change to plain UTC, not a seasonal one, so every Worker that renders a wall-clock time for Morocco or Western Sahara will be an hour late from 2026-09-20 onward, indefinitely.
Why this is easy to miss
The failure is silent.
Dateinstants stay correct — only the wall-clock label is wrong — so responses look plausible and nothing throws. In our case, maghrib for18:34Zrendered as19:34local instead of18:34.It also does not reproduce under some local toolchains. Bun already carries 2026c, so our unit tests and validation harness passed while production was wrong.
Reproduction
Observed on
workerd1.20260906.1 (also on 1.20260730.1, and reported against production Workers on 2026-08-25):{ "before_casablanca": "GMT+01:00", "after_casablanca": "GMT+01:00", "after_el_aaiun": "GMT+01:00" }Expected, per 2026c:
{ "before_casablanca": "GMT+01:00", "after_casablanca": "GMT", "after_el_aaiun": "GMT" }Source for the rule
[PROPOSED] Morocco goes to plain UTC on 2026-09-20thread ontz@iana.org(Paul Eggert, 2026-07-04).Both
Africa/CasablancaandAfrica/El_Aaiunare covered by the decree, and both are affected here.Impact
Anything that formats a Moroccan wall-clock time in a Worker: scheduling, calendar exports, business-hours logic, prayer times. Because
Dateinstants remain correct, existing tests that compare instants will not catch it — only tests that assert on rendered local time will.What we did meanwhile
We added a runtime-conditional override that formats Casablanca/El_Aaiun instants at or after
2026-09-20T01:00:00Zin UTC, but only while the runtime disagrees, so it disables itself once the embedded tzdata catches up. Happy to share that if useful, though the real fix is the tzdata bump.Please let me know if a minimal repro repo would help.