首页 › programming › 时区:程序员头号深坑

时区:程序员头号深坑——一条被转发了十三年的神作《The Problem with Time & Timezones》深度解读

说明:本文所选视频因网络核验受限,播放量、发布日期等数据均标注“据频道页面”,未能实时抓取精确数值,读者可自行到频道页核对。

概述

编程界有一条被反复推荐了十余年、至今仍活跃在各大社区“程序员必看”清单里的视频:Computerphile 的《The Problem with Time & Timezones》。主讲人 Tom Scott 用一块贴满打印纸的玻璃板和十几分钟,讲透了一件反直觉的事:你以为“时间”是宇宙规定好的客观常量,但在工程世界里,它是由物理学、天文学和各国政治临时协商出来的一个“公约数”。看懂这条视频,你收获的不只是“怎么存时间戳”的技巧,而是一套识别“隐藏复杂度”的方法论——为什么有的系统改一个字段就能上线,有的系统却因为一次时区规则变更全线崩溃。本文按视频的叙事顺序逐层拆解,追溯背后的真实标准与工程实践,并补上视频发布十年来世界发生的新变化。

视频基本信息

项目 内容
视频标题 The Problem with Time & Timezones(可译《时间与时区的问题》)
频道 Computerphile(Brady Haran 团队制作的计算机科普频道,百万级订阅,据频道页面)
主讲人 Tom Scott(英国科普创作者、主持人)
发布时间 2013年11月(据频道页面,未核验精确日期)
播放量 数百万量级,长期被视为程序员必看经典(据频道页面,未实时核验)
观看链接 https://www.youtube.com/watch?v=-5wpm-gesOY

需要说明:这不是一条最近60天内的新片,而是一条“常青神作”。它至今仍值得做全文深读,恰恰因为它讲的问题十三年来一个都没有消失——2023年黎巴嫩的时区切换风波、闰秒在2035年前被废除的国际决议,都在继续给这条视频“续命”。

一、核心主张拆解:他把“时间”拆成了四层地狱

要点1:“23:30 加一小时等于午夜”——这个直觉在地球上是错的

视频开场,Tom Scott 站在玻璃板前做一个大多数人从未怀疑过的算术:晚上23:30,过一小时就是午夜零点,对吧?随后他把这张“理所当然”逐格撕碎。地球上的时区偏移并不是整整齐齐的整小时:印度是 UTC+05:30,尼泊尔是 UTC+05:45,南澳大利亚的阿德莱德平时是 UTC+09:30(进入夏令时变 +10:30),而新西兰的查塔姆群岛是 UTC+12:45。在这些地方,“23:30 再过一小时”要么已经是次日 00:30,要么根本对不上任何“午夜”的概念。他真正想说的是:哪怕最简单的“时间加法”,也隐含着一个前提——你在哪。所有拿本地时间做算术的代码,都在无意识地假设一个不存在的均匀世界。

要点2:幽灵时段与重复时段——DST 让“本地时间”失去唯一性

第二层地狱来自夏令时(DST)。春季切换的那一夜,时钟从 01:59 直接跳到 03:00,也就是说“01:30”这个时刻在当年根本不存在;秋季切换的那一夜,时钟从 02:59 拨回 02:00,“01:30”会出现两次。Tom Scott 的关键论点是:一个裸的本地时间字符串,比如“某年3月31日 01:30”,本身无法自证身份——它可能是不存在的时刻,也可能是两个不同物理时刻中的任意一个。解释它的唯一办法,是额外附带“时区ID + 当时生效的规则”。这就引出了全片最重要的一句话级结论:本地时间不是时间,本地时间是“待解释的数据”。

要点3:政治随时重画时间——萨摩亚凭空消失的一天

第三层地狱最魔幻:时区的边界和规则由各国政府决定,而且真的会改。Tom Scott 用了当时刚发生不久的案例——2011年12月底,萨摩亚(连同托克劳)决定整体换边:为了和最大贸易伙伴澳大利亚、新西兰共用工作日,它从国际日期变更线东侧跳到西侧,时区从 UTC-11 改为 UTC+13,结果2011年12月30日(星期五)这一天在萨摩亚的日历上被整段删除,12月29日的第二天直接是12月31日。对当地居民这是一次商业划算的“跳日”,对全世界的日历软件这是一次终极压力测试:你的代码能处理“某个国家历史上不存在的一天”吗?据当年 BBC 等媒体报道,这次跳日如期执行,旅游业者还特意宣传“来萨摩亚丢掉一天”。这个案例的工程含义在于:时间规则不是物理常数,它会在没有任何技术公告的情况下 overnight 改变。

要点4:闰秒——物理时间与工程时间之间的最后一秒拉扯

第四层地狱藏在玻璃板的另一张纸下:闰秒。地球自转并不均匀,为了让“民用时钟 UTC”与“地球实际朝向 UT1”的偏差不超过0.9秒,国际计量机构会不定期在6月30日或12月31日的末尾插入一秒——那一刻全球时钟显示 23:59:60,然后才到 00:00:00。截至这条视频发布(2013年),人类已经插入过25个闰秒,最近的一次是2012年6月30日。而2012年那次闰秒直接导致了真实事故:据 Ars Technica、CNET 等媒体报道,Reddit、Mozilla、LinkedIn 等一批知名网站当晚因内核时钟处理异常出现宕机或服务异常。Tom Scott 借此点出问题的本质:闰秒让“分钟永远60秒”这个程序员的底层假设失效,时钟可能原地走慢一秒甚至往回走——一切依赖“时间单调递增”的代码都在裸奔。

要点5:Tom Scott 的处方——存 UTC,最后才转换

讲完四层地狱,他给出了全片的行动纲领,也是这条视频被反复引用的原因:在系统内部一律存储 UTC(绝对时间),只有在最后要展示给人看的瞬间,才转换成本地时间。任何“本地时间入库”的做法,都是在把一颗未来必然引爆的地雷埋进数据库。同时他提醒:与时区相关的规则数据必须保持可更新——因为规则一定会变。这句处方看起来朴素,但它是此后十年几乎所有时间库(Java 的 java.time、.NET 的 Noda Time 等)共同坚持的第一原则。

二、知识与理论溯源:视频背后的真实标准与工程史

UTC 的定义链条。 现代民用时间 UTC 的构造是“原子时 + 闰秒”:TAI(国际原子时)由全球数百台原子钟加权平均而来,均匀但与地球脱钩;UT1 反映地球真实自转;UTC 取原子时的均匀性,再通过插入闰秒把与 UT1 的偏差压在0.9秒以内。闰秒的决定权在国际地球自转服务(IERS),度量衡体系的最高决策在国际计量大会(CGPM)。这条链条解释了视频里的核心张力:工程想要均匀的时间,而民用 wanting 太阳当头的时间,两者靠“打补丁”维持一致。

IANA tzdata——全世界的时区真相源。 视频里“规则会变”的载体,就是互联网号码分配机构(IANA)维护的时区数据库 tzdata(前身是 Arthur David Olson 于1980年代发起的 Olson 数据库)。它记录了全球数百个时区的历史与未来规则,每年发布多个版本,被 Linux、macOS、Java、ICU、浏览器等几乎所有主流平台引用。一个鲜为人知的插曲:2011年,一位占星师 David Brown 就历史时区数据的准确性起诉数据库维护方,导致 tzdata 一度被官方撤下,最终由 ICANN 出面接管托管,这场风波被当年多家科技媒体报道。一个自由软件数据库险些因诉讼停摆,这件事本身就是“时间基础设施有多脆弱”的注脚。

POSIX time_t 与 Y2038。 Unix 系统用“自1970-01-01起的秒数”表示时间,且 POSIX 标准刻意规定“每天都是86400秒”,即 Unix 时间不感知闰秒——这正是2012年闰秒之夜事故的技术根源之一(NTP 让系统时钟回拨,某些程序陷入忙循环)。而32位有符号 time_t 将在 2038-01-19 03:14:07 UTC 溢出,即著名的 Y2038 问题;Linux 内核自 5.6 版本起为32位架构补上了64位 time_t 系统调用,迁移仍在进行中。

标准与库的集体纠错。 视频发布前后,业界其实已在系统性还债:iCalendar 标准(RFC 5545)用“本地时间 + TZID”表达重复日程;Java 8(2014年)借 Stephen Colebourne 的 Joda-Time 经验推出全新的 java.time API(JSR-310),用 Instant(绝对时间)、ZonedDateTime(带规则的时间)等类型把“绝对时间”与“墙上时间”显式分离;.NET 社区则在 Jon Skeet 长期维护的 Noda Time 中实现同样理念;PostgreSQL 的 timestamptz 类型文档明确建议时间戳一律带时区语义(内部以 UTC 存储)。Tom Scott 在2013年喊出的处方,此后变成了整个行业的默认施工规范。

三、批判性审查:哪些主张已被验证,哪些需要打补丁

证据充分的部分。 “存 UTC、展示层才转换”是被大量事故反复验证的行业共识:2012年闰秒之夜的大面积宕机(Reddit、Mozilla 等)、2016年12月31日闰秒之夜 Cloudflare 的 DNS 故障(其官方博客复盘:闰秒让时钟回拨,证书有效期字段算出了负数 TTL)、以及2023年3月黎巴嫩政府临时宣布推迟夏令时又朝令夕改导致航班与学校混乱的事件(据 Reuters、BBC 报道)——三起事故的共同死因都是“代码假设了时间的某种均匀性或规则稳定性”。这条视频的核心论断在事后十年里没有一条被推翻。

需要补充而非照搬的部分。 视频给出的“存 UTC”是必要条件而非充分条件。对“未来的重复事件”(比如“每周一早上9:00例会”),正确做法恰恰不是先换算成 UTC 存储,而是存“本地墙上时间 + IANA 时区ID”,在每次发生时按最新 tzdata 规则重新换算——否则一旦该国改了夏令时,你的日程就会整体漂移一小时。这正是 RFC 5545 的建模方式,也是后来 Jon Skeet 等人在演讲中反复强调的进阶原则。Tom Scott 在2013年的叙述里没有展开这一层,观众若只记住“一律转 UTC”,就会在日历类业务里踩坑。

时效性更新。 视频里“闰秒将长期困扰我们”的隐含预期已经改变:2022年11月,第27届国际计量大会通过第4号决议,要求在2035年前废除闰秒机制,国际业界将另行商定新的协调方式。此外,2011年白俄罗斯临时取消夏令时切换导致大量 Outlook 日程错乱(微软为此紧急发补丁,据当年报道)、土耳其2016年起固定 UTC+3、摩洛哥2018年起常年保持 UTC+1(斋月期间临时回调)——每一个案例都在给视频的第三层地狱追加新证据。

真实存在的争议。 废除闰秒并非没有代价:反对者指出,若 UTC 不再贴着 UT1 打补丁,几十年后民用时间与太阳时的偏差会累积到肉眼可感,届时可能需要一次性的“闰分”级调整;而金融、航天等高精度领域(如不插闰秒的 GPS 时间,目前与 UTC 相差18秒)永远需要在“绝对均匀”与“民用一致”之间自行选边。这些争议说明:视频里那个看似纯粹的“时间问题”,本质是物理、工程与治理的三方谈判,且谈判还远未结束。

四、认知提升与实用启示

第一,建立“三段式”时间建模习惯。 入口处把用户的输入显式拆成“本地墙上时间 + 时区ID”两个信息,绝不接收裸字符串;存储时区分两类——已发生的时刻转成 UTC/epoch 入库,未来的重复事件存“本地时间 + IANA 时区ID”;展示层在最后一刻用最新的 tzdata 规则渲染。判断标准一句话:凡是“已经发生的”存绝对时间,凡是“还要按当地日历发生的”存本地时间加规则引用。

第二,把视频里的坑变成测试用例集。 一个合格的时间相关系统,测试集里应该至少有:不存在的时刻(春季 01:30)、重复的时刻(秋季 01:30)、非整点偏移(+05:45)、某个国家不存在的一天(萨摩亚的2011-12-30)、闰秒时刻 23:59:60 与时钟回拨、以及 Y2038 边界(2038-01-19)。这些用例不需要多,但每一条都对应一类真实生产事故——写一次,护终身。

第三,把“规则会变”当作架构输入,而不是意外。 时区数据要像安全补丁一样定期更新(订阅 tzdata 发布),依赖派生时间结果的数据要设计成“可按新规则重算”;在产品层面,一切与日历、账单、日志排序相关的功能,评审时都应多问一句:“如果某个国家明天改了时区,我们的数据会怎样?”——这条提问方式,就是这条视频十三年不过时的原因:它教的不是某个 API 的用法,而是对一类隐藏复杂度的永久免疫。

五、视频论证结构图

flowchart TD
    A["用户输入:本地墙上时间 + 时区ID"] --> B{"事件属于过去,还是未来且会重复?"}
    B -->|"过去或一次性"| C["换算为 UTC 入库"]
    B -->|"未来且重复"| D["存本地时间 + IANA时区ID<br/>(RFC 5545 的做法)"]
    C --> E[("数据库:UTC 或 epoch")]
    D --> F["读取时用最新 tzdata 规则换算"]
    F --> E
    E --> G["展示层:最后一刻才转本地时区"]
    G --> H{"边界陷阱检查"}
    H -->|"非整点偏移"| I["印度 +05:30<br/>尼泊尔 +05:45<br/>查塔姆 +12:45"]
    H -->|"夏令时切换日"| J["不存在的 01:30<br/>重复出现的 01:30"]
    H -->|"闰秒"| K["23:59:60<br/>时钟回拨一秒"]
    H -->|"32位 time_t"| L["2038-01-19 03:14:07 溢出"]
    I --> M["存 UTC ≠ 万事大吉:<br/>规则是政治与工程的谈判结果"]
    J --> M
    K --> M
    L --> M

延伸阅读

  1. Oracle 官方 java.time(Date-Time API)教程 — 把“绝对时间/墙上时间分离”落到代码层面的最佳入门:https://docs.oracle.com/javase/tutorial/datetime/
  2. PostgreSQL 官方文档:日期/时间类型 — timestamptz 的真实语义与官方建议:https://www.postgresql.org/docs/current/datatype-datetime.html

参考来源

  1. The Problem with Time & Timezones - Computerphile(视频页) — 本文解读对象,Tom Scott 主讲
  2. Cloudflare: How and why the leap second affected Cloudflare DNS — 2016年闰秒事故官方复盘
  3. Google Official Blog: Time, technology and leaping seconds — Google 提出 leap smear 方案的原始文章
  4. IANA Time Zone Database — 全球时区规则权威数据源(tzdata)
  5. BIPM: CGPM 2022 第4号决议 — 2035年前废除闰秒的国际决议

本文由「51学通信」技术团队出品。51学通信由通信行业18年老兵爱卫生(微信ID: gprshome201101)维护,聚焦5G/6G核心网、3GPP标准解读、通信前沿技术深度分析。 出版作品有《5G核心网原理与实践》《IMS原理与实践》等4本通信专业书籍。知识星球「51学通信」提供深度技术答疑和行业洞察。

[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。

51学通信知识星球海报-扫码加入