首页 › programming › 别存本地时间:一条时区神课深读

别存本地时间:一条时区神课深读

概述

程序员社区流传一个说法:世界上有两类难题,一类是缓存失效和命名,另一类是时区。而在 YouTube 上,把“时区到底难在哪”讲得最透彻的,是 Computerphile 频道的一条经典视频《The Problem with Time & Timezones》。这条视频没有炫技动画,就是一个白板加一段演示,却常年被程序员反复挖出来重看,长期位居该频道的播放量前列(据频道页面)。它值得读的原因很简单:它讲的不是某个框架的用法,而是几乎所有日历、日程、订单、日志系统都会踩的那颗雷——为什么“存本地时间”是一个看起来无害、实际上必然翻车的决定。本文带你完整重走这条视频的论证路线,再补上视频没来得及展开的几层。

视频基本信息

项目 内容
英文标题 The Problem with Time & Timezones
中文标题 时间与时区的问题
频道 Computerphile
主讲人 Tom Scott(英国知名科普创作者)
发布时间 2017 年(据频道页面)
播放量 数百万级,长期位居频道前列(据频道页面,未逐日核对)
链接 youtube.com/watch?v=-5wpm-gesOY

一条老视频为什么常看常新

先说结论:这条视频的核心论点,七年过去不但没有过时,反而越来越“真”。因为视频里警告的那类事故,今天仍在每个新框架、新数据库、新业务的身上重演——新的开发者换了一茬又一茬,雷还是那颗雷。

Tom Scott 的讲法非常克制。他不堆术语,而是从一个最朴素的场景出发:你写了一个日程应用,用户说“每天早上九点提醒我”。你怎么存这个时间?绝大多数人的第一反应是:存"09:00"这个字符串,或者存一个时间戳。视频用不到二十分钟,把这两个看似合理的答案逐一拆掉。

核心主张拆解:四记重拳

第一拳:拨钟日不存在“物理时间”

以英国为例,每年三月末的某个凌晨,时钟会从一点直接跳到两点(进入夏令时);十月末的某个凌晨,时钟又会从两点退回一点(退出夏令时)。这意味着:

视频里最扎心的演示就在这里:一个按“本地时间加一天”做循环日程的程序,跨过拨钟日之后,会议会整体漂移一小时。用户看到的是“我的提醒凭什么变了”,而代码看起来一行都没错。

第二拳:时区不是偏移量,是一张会变的规则表

很多人以为“时区 = UTC+8”这样一组偏移数字。视频明确指出这是幻觉:时区的本质是一整套由各国政府随时可以修改的规则——什么时候进入夏令时、什么时候退出、甚至整个时区划到哪里,都是行政决定,不是物理决定。

最极端的例子是萨摩亚:2011 年 12 月,这个国家为了和澳大利亚、新西兰的贸易伙伴对齐工作日,整条时区从 UTC−11 直接切到 UTC+13,全国日历上整个跳过了 12 月 30 日这一天——前一天是周四,一觉醒来是周六。工程师对“连续性”的一切假设,在行政命令面前不值一提。类似的规则调整,几乎每年都在全球某处发生。

第三拳:全世界的软件靠一张“民间规则表”续命

政府改规则,软件怎么办?视频引出了这个体系里真正的英雄:IANA 时区数据库(tz database,俗称 tzdata / Olson 数据库)。这是一份由志愿者和研究者维护的规则表,收录了全球几百个时区的现行规则和历史变更,政府一改规则,这里就跟进更新,然后操作系统、浏览器、编程语言运行时在全球范围内分发更新。

换句话说:你以为你的代码在“算”时区,其实是 tzdata 在“查”时区。你的程序里唯一该做的,是别把规则硬编码进自己的代码,而是随时查最新的规则表。

第四拳:解法——但比“存 UTC”更细一层

视频给出的答案分两种情况,这也是它比网上大多数“一句话教程”高明的地方:

  1. 记录“已经发生的时间点”(日志、下单时间、消息发送时间):一律存 UTC 时间戳,展示时再按用户时区换算。
  2. 记录“未来要发生的日程”(会议、航班、提醒):不能只存 UTC!因为未来的 UTC 时刻依赖“到时候政府怎么定规则”——如果某个国家明年改了夏令时政策,你现在算出的 UTC 值就是错的。正确做法是存当地时间 + 时区名(例如“09:00,Europe/London"),到展示或触发时再换算。

第二个结论是这条视频真正的“神来之笔”,也是被最多观众漏掉的一层。它推翻了“存 UTC 就万事大吉”的粗暴口诀。

知识与理论溯源

视频里的每一条主张,背后都有扎实的工程与历史依据:

批判性审查

证据充分的部分:时区规则可被政府随时修改(tzdb 的更新日志公开可查)、夏令时边界的“不存在/重复”时间问题(任何一本权威时间处理文档都会确认)、“存 UTC + 边缘换算”的行业共识、以及“未来日程必须存当地时间+时区”的结论——这些是跨语言、跨平台的工程共识,没有争议。

被简化或需要补充的部分:

  1. “永远存 UTC”是被观众简化的版本。视频其实自己论证了例外(未来日程),但很多读者只记住了口诀。生日、营业时间、合同生效日这类“墙上时间”业务,存 UTC 反而会出错——你记录的本来就是“当地那个时刻”,不是某个物理瞬间。
  2. 视频没讲系统里还有“第二台钟”。计算耗时(性能统计、超时控制)必须用单调时钟(monotonic clock),不能拿系统时间做减法——否则 NTP 校时或闰秒一来,你的耗时算出负数。这是同一主题下视频没覆盖的一层。
  3. “时区名”和“固定偏移”不是一回事。+08:00 是一个数字,Asia/Shanghai 是一整套含历史和夏令时规则的条目。接口设计里混用两者,是比存本地时间更隐蔽的坑。
  4. 闰秒问题的结局正在改写。UTC 历史上靠“加一秒”追平地球自转误差,而 2022 年国际计量大会(CGPM)已通过决议,计划在 2035 年前取消闰秒机制;科技巨头则早已用“跳秒抹平”(smearing)技术自行消化。视频年代较早,未涉及这个后续——这是“看过视频还能多懂一层”的典型增量。
  5. 历史数据的可靠性不均。tzdb 对 1970 年以前的历史时区数据只做到“尽力而为”,做历史数据分析的人需要知道这条边界。

认知提升与实用启示

第一条:给数据库立规矩。 所有“时间点”字段一律用 UTC 时间戳(PostgreSQL 用 timestamptz,它内部就是存 UTC),接口传输一律用 ISO 8601 带"Z"的格式,明文禁止存"2026-09-26 09:00:00"这类裸本地字符串。这条规矩写进团队规范,能消掉未来八成的时区事故。

第二条:日历类业务,存“当地时间 + IANA 时区名”。 你要保存的是用户当时指的那个墙上时间,以及他所在时区的完整规则条目。触发和展示时再换算。永远记录用户当时的时区选择,因为用户会搬家、会旅行。

第三条:把边界时间塞进测试集。 每个处理时间的函数,都应该被“不存在的时间”(春令时凌晨)、“重复的时间”(秋令时凌晨)和“萨摩亚跳日”三种输入拷打一遍。测耗时一律用单调时钟。这三个测试用例的成本不到半小时,防住的是半夜被告警叫醒的凌晨。

视频论证结构图

flowchart TD
    A[日程App存了本地时间] --> B[春季拨快<br/>有些时间不存在]
    A --> C[秋季拨慢<br/>同一时刻出现两次]
    B --> D[只存偏移量并不够]
    C --> D
    D --> E[政府随时改规则<br/>时区是张会变的表]
    E --> F[萨摩亚整日跳过<br/>规则可被整条推翻]
    E --> G[IANA时区数据库<br/>全球软件同步更新]
    F --> H[解法一<br/>时间点存UTC]
    G --> H
    G --> I[解法二<br/>未来日程存当地时间加时区]
    H --> J[展示层再换算<br/>别硬编码规则]
    I --> J
    J --> K[例外提醒<br/>生日类业务别换算]

延伸阅读

  1. IANA 时区数据库官方页(iana.org/time-zones)——视频主角本尊,可查每一次规则变更的发布记录。
  2. MDN 的 Date 文档(developer.mozilla.org)——理解 JavaScript 里这套坑的现代解法(Intl API 如何替代手写偏移)。

参考来源

  1. The Problem with Time & Timezones — Computerphile — 本文解读的这条视频本体,播放与发布数据以频道页面为准
  2. Computerphile 频道主页 — 视频所属频道,计算机科普领域头部频道
  3. IANA Time Zone Database — 视频中提到的全球时区规则表官方发布页
  4. MDN Web Docs: Date — 时间存储与换算的工程实践参考
  5. ISO 8601 — Wikipedia — 国际日期时间表示标准,"Z"后缀的含义

本文由「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学通信知识星球海报-扫码加入