夏令时的存在与切换日期不统一
别名: 夏令时切换 · 时区规则 · 本地时间间隙 · DST fold
概念解释
夏令时切换(daylight-saving time transition)是某个地区的民用时钟按规则改变 UTC 偏移的事件。并非所有地区实行夏令时,实行地区的开始、结束日期和偏移幅度也不统一,规则还会被临时或永久修改。处理时间的关键不是询问用户是否“喜欢夏令时”,而是区分绝对时间点(instant)、不含时区的本地日期时间(local date-time)与 IANA 时区标识,并为本地时间的间隙(gap)和折叠(fold)定义策略。
机制
时钟向前跳时,一段墙上时间不存在,形成 gap;时钟向后拨时,一段墙上时间出现两次,形成 fold。把 2026-xx-xx 02:30 与固定 UTC 偏移保存,既不能说明 gap 中如何处理,也不能在 fold 中选择较早还是较晚的瞬时。IANA Time Zone Database 用地区标识和版本化规则把 instant 映射为当地时间;政治机构改变时区边界、UTC 偏移或夏令时规则后,同一个未来本地时间可能对应新的 instant。重复事件“每周当地 09:00”与“每隔 168 小时”因此不是同一语义。
怎么研究
建立以 IANA 时区和 tzdb 版本为轴的转换测试,覆盖无夏令时区、向前与向后切换、非一小时偏移、临时规则变化、跨时区参与者和跨越切换点的重复事件。对每个样本分别断言输入的 local date-time、解析策略、所得 instant、UTC 偏移和回显文本。用性质测试验证 instant→本地时间→instant 的往返;对 local date-time→instant 则显式期待零个、一个或两个候选。可用性研究应观察用户能否理解“时间不存在”或“此时间出现两次”的选择,以及通知和日历更新是否建立正确预期。
边界
固定偏移如 UTC+08:00 不是地区时区,不能表达未来规则;三字母缩写也可能歧义。tzdb 会更新已知历史和预测未来,但早期历史可能不完整,未来规则也可能在活动创建后改变。一次性跨时区会议通常以 instant 为承诺,地点和时区用于显示;按当地作息重复的营业、课程或提醒通常以 local date-time、时区和重复规则为承诺。两者不能用同一种自动重算策略。时区选择也不应从语言、国籍或当前 UTC 偏移唯一推断。
怎么落地
- 一次性已确认事件保存 instant,并保存用于解释和显示的 IANA 时区;按当地时间重复的事件保存 local date-time、IANA 时区、重复规则以及 gap/fold 处理政策。
- gap 中不要静默生成不存在的时间;提示用户改选,或明确采用“移到跳转后第一个有效时间”等已公布策略。fold 中让用户区分较早/较晚实例,或显示 UTC 偏移以消歧。
- 使用维护中的 tzdb,不把固定偏移或时区缩写当作时区标识;记录计算所用规则版本。规则更新后,只按事件承诺语义重算当地时间重复事件或尚未固化的本地时间,保持已确认一次性事件的 instant 不变;生成差异,并通知时间发生变化的参与者。
- 在每个支持地区的真实切换边界前后做创建、编辑、排序、提醒、倒计时和导出测试;覆盖客户端与服务端 tzdb 版本不一致、离线旧数据和跨区查看。客户端版本过旧时以带版本号的服务端解析结果为准,提交前显示差异或阻止静默确认;验证不会重复执行、漏执行或错序。