2026年11月1日,不列颠哥伦比亚、阿尔伯塔、曼尼托巴和西北地区没有把时钟往回拨。它们现在分别固定使用 UTC-7、UTC-6、UTC-5 和 UTC-6。育空从2020年起就全年使用 UTC-7。这不是全国政策,比如安大略仍然跟随北美的季节性作息。
对一个人来说,这件事意味着少跟微波炉上的时钟较劲。对一个软件团队来说,它意味着未来会议、周期任务、报表、结算窗口,以及每一个理直气壮存下“09:00”却不先问一句“哪里的09:00”的系统,脚下的民用时间规则被换掉了。
好消息是时区数据库存在。坏消息是它需要被安装、被更新,还得被当成产品的一部分。时间这东西,看来又有依赖了。
变的不只是标签
叫法各不相同。不列颠哥伦比亚把新时区叫太平洋时间,阿尔伯塔叫 UTC-6 阿尔伯塔时间,曼尼托巴叫 UTC-5 曼尼托巴标准时间——尽管它保留的其实是原先的夏令时。这种命名可以理解,但它也提醒人:缩写不是可靠的时区模型。
在数据和代码里,用 IANA 时区标识符,比如 America/Vancouver、America/Edmonton、America/Winnipeg。别拿 PST、MST 或者一个裸偏移量去替代某个地点的规则。那些标签是戴着工牌的小陷阱。
加拿大不是孤例,规则也不一起动。墨西哥2022年在大部分地区结束了季节性调时,而北部许多边境市镇保留了季节性作息以对齐美国。古巴2026年10月的 IANA 更新说,它将保持 UTC-4 直到2027年11月7日,而不是在这个周末回拨。与此同时,欧盟仍在调钟:2018年那份停止调时的提案至今没有最终决定,也没有时间表。
所以“夏令时要结束了”这句话,在代码评审里太含糊,没法用。真正的问题永远是:哪个司法辖区、哪个基于地点的时区、哪个生效日期,以及这个运行时认识的是哪一版规则。
IANA 时区数据库把不列颠哥伦比亚记在 2026b 版本,阿尔伯塔在 2026c,西北地区在 2026d,曼尼托巴在 2026e。这个顺序有点耐人寻味。政府宣布变更,时区维护者发布规则,操作系统、语言运行时、容器、浏览器、手机、日历厂商和长寿命服务各自在不同时间跟上。中间某个环节,一个半年前排好的周期会议,开始跟一台上个财年之后就没重启过的笔记本谈判。
这不是时钟问题,是一个换了更好听名字的部署问题。
哪些地方会坏
把时间戳存成 UTC,对于“发生在某个具体瞬间的事件”仍是正确的默认做法。但它保不住“在温哥华每个工作日09:00运行”这类规则的含义。这种规则同时需要本地时间和一个 IANA 时区。一个 UTC 时间戳单独存在时,没法告诉你辖区改规则之后组织者原本想表达什么。
我会先检查那些带有未来意图的系统:
- 规则更新之前创建的周期日历事件和提醒。
- 用本地时间定义的类 cron 任务。
- 描述本地营业日的薪资、计费、市场、预订和服务窗口。
- 按本地日期或小时分组的报表。
- 自带时区数据的移动端和桌面客户端。
- tzdata 包过期的容器和旧主机。
微软针对加拿大变更的官方指引,是让 Outlook 用户选择新时区,并核对或迁移未来和周期会议。一个日历厂商给出这么直接的产线测试用例,不太常见。别因为一个事件今天下午显示正常,就假定它安全。
一个小模型,省一次大事故
对于排定的预约或周期业务规则,把本地含义和你算出的瞬间一起留着。
示例模型里,时区是业务规则的一部分:本地开始时间写成 2027-01-15T09:00,时区写成 America/Vancouver。用当前的 IANA 时区数据库解析它,再把每次发生对应的 UTC 瞬间存下来。
这个例子故意无聊。当客户期待一个09:00的预约还是09:00时,无聊是特性。应用可以为每次发生算出 UTC 瞬间,但它应当保留产生这个瞬间的本地规则和时区。如果时区数据变了,重新生成未来的发生项,并在悄悄挪动任何人的会议之前,把差异显示出来。
还要围绕切换点测试日历。在生效日期前后各造夹具,包括一个在更新前创建、跨越生效日期的周期事件。断言本地显示、UTC 瞬间、通知时间和下游集成载荷。一个只检查开发者当前时区里 new Date() 的通过单测,就是这么把时间提拔成首席工程师的。
实操清单
- 盘点每个服务从哪里拿时区数据:操作系统、容器基础镜像、运行时、数据库、客户端或厂商 API。
- 有意识地打补丁并记录版本。IANA 发布规则,但它不会把规则瞬移进一个六个月大的容器。
- 瞬间存 UTC。只要是人设定的未来本地时间规则,就同时存一个基于地点的 IANA 时区。
- 规则变更后,重新计算并复核未来的周期事件,尤其注意厂商更新之前创建的那些。
- 测试本地业务边界,而不只是时间戳格式。
一年一度的调钟可能在更多地方消失。民用时间并没有变简单,它变得更显式了——对所有人都是更好的交易,除了那些一直假装 PST 是一种数据类型的代码。
热门跟贴