#!/usr/bin/env python3 """Which Windows -> IANA mapping tables know Windows' three new Canadian zone IDs? Windows' fix for the 1 November 2026 changes adds new zones instead of editing "Mountain/Pacific/Central Standard Time". Software that maps the Windows ID to an IANA name from an older table finds nothing for a machine switched to them. Stdlib only; reads public URLs; writes nothing. Pinned URLs reproduce the frozen result; "moving" rows show today's branch heads. Prints one row per source with the count of each ID (ASCII or UTF-16LE, since ICU .res and .NET literals are UTF-16) and the sha256 of the bytes read. python3 -I windows-ids-check.py """ import gzip import hashlib import io import sys import urllib.request import zipfile IDS = ("Alberta Standard Time", "British Columbia Standard Time", "Manitoba Standard Time") RAW = "https://raw.githubusercontent.com" SOURCES = [ # (label, kind, url) ("CLDR main (commit c4bb2c199c, 2026-10-09)", "pinned", f"{RAW}/unicode-org/cldr/c4bb2c199c/common/supplemental/windowsZones.xml"), ("CLDR 49 beta4 (release-49-beta4)", "pinned", f"{RAW}/unicode-org/cldr/release-49-beta4/common/supplemental/windowsZones.xml"), ("ICU 78 (maint/maint-78)", "moving", f"{RAW}/unicode-org/icu/maint/maint-78/icu4c/source/data/misc/windowsZones.txt"), ("ICU 79 (maint/maint-79)", "moving", f"{RAW}/unicode-org/icu/maint/maint-79/icu4c/source/data/misc/windowsZones.txt"), ("ICU 79.1rc (release-79.1rc)", "pinned", f"{RAW}/unicode-org/icu/release-79.1rc/icu4c/source/data/misc/windowsZones.txt"), ("ICU tz update files 2026e (windowsZones.res)", "pinned", f"{RAW}/unicode-org/icu-data/bae5ca647fa41703393dbf00240ec1b807a9c353/tzdata/icunew/2026e/44/le/windowsZones.res"), ("tzlocal 5.4.4 (tag 42dfd05)", "pinned", f"{RAW}/regebro/tzlocal/42dfd05/tzlocal/windows_tz.py"), ("tzlocal master", "moving", f"{RAW}/regebro/tzlocal/master/tzlocal/windows_tz.py"), ("OpenJDK master tzmappings.override", "moving", f"{RAW}/openjdk/jdk/master/src/java.base/share/data/tzdata/tzmappings.override"), ("PostgreSQL master initdb win32 map", "moving", f"{RAW}/postgres/postgres/master/src/bin/initdb/findtimezone.c"), ("Go master abbreviation table", "moving", f"{RAW}/golang/go/master/src/time/zoneinfo_abbrs_windows.go"), ("TimeZoneConverter 8.0.0 (NuGet, net8.0 dll)", "pinned", "https://api.nuget.org/v3-flatcontainer/timezoneconverter/8.0.0/timezoneconverter.8.0.0.nupkg"), ("TimeZoneConverter 7.2.0 (NuGet, net8.0 dll)", "pinned", "https://api.nuget.org/v3-flatcontainer/timezoneconverter/7.2.0/timezoneconverter.7.2.0.nupkg"), ] def fetch(url): req = urllib.request.Request(url, headers={"User-Agent": "windows-ids-check"}) with urllib.request.urlopen(req, timeout=60) as r: return r.read() def payload(url, data): if url.endswith(".nupkg"): z = zipfile.ZipFile(io.BytesIO(data)) return z.read("lib/net8.0/TimeZoneConverter.dll") if data[:2] == b"\x1f\x8b": return gzip.decompress(data) return data def count(data, s): return data.count(s.encode("ascii")) + data.count(s.encode("utf-16-le")) def main(): print("source | kind | " + " | ".join(IDS) + " | sha256(bytes read)") failed = 0 for label, kind, url in SOURCES: try: raw = fetch(url) except Exception as e: # report and keep going; a missing row stays UNKNOWN print(f"{label} | {kind} | UNKNOWN ({type(e).__name__}: {e}) | {url}") failed += 1 continue data = payload(url, raw) counts = [count(data, s) for s in IDS] print(f"{label} | {kind} | " + " | ".join(str(c) for c in counts) + f" | {hashlib.sha256(raw).hexdigest()[:16]}") return 1 if failed else 0 if __name__ == "__main__": sys.exit(main())