2026年3月8日到3月29日,纽约和伦敦之间凭空多出一小时时差。不是地理原因,是两个大陆按下了不同步的按钮。
美国切到EDT,欧洲还在CET。全球开发者集体踩进一个叫"DST Gap"的陷阱——夏令时缝隙。你的倒计时可能正对着错误的时间做正确的事。
UTC是你的母语,本地时间是方言
服务器住在机房里,没有日出日落。它只该说UTC(协调世界时),一种靠原子钟定义、拒绝夏令时的时间标准。
GMT(格林尼治标准时间)常被混用,但GMT是时区,偶尔还过夏令时;UTC是标准,永远+00:00。存数据用UTC,争论这个属于浪费时间。
原文作者举了个Kotlin的反面教材:LocalDateTime.now()——谁的"现在"?你的?服务器的?东京的?歧义本身就是bug。
正确姿势是Instant.now(),返回UTC时间戳。无聊,但可靠。
事件有故乡,时间要"落户"
假设你在做东京证券交易所的开市提醒。09:00 JST(日本标准时间)是东京的钟表,不是你的。
第一步:锁定事件的原生时区。用ZonedDateTime把日期、时间、时区打包成一个完整对象。
第二步:转成UTC存起来。这时候你拿到一个锚点——2026-03-24T00:00:00Z,后面的Z就是UTC的签名。
倒计时怎么算?两个Instant相减,底层全是UTC,不会被夏令时偷袭。
但显示给用户的本地时间会变。日本不过夏令时,幸运儿。可你的用户如果在布拉格,冬天看到CET(UTC+1),夏天看到CEST(UTC+2),同一串UTC时间戳,屏幕上跳出一小时。
客户端是最后的战场
浏览器里的toLocaleString()是双刃剑。它自动处理时区转换,也意味着你的"09:00"可能在用户屏幕上变成"08:00"或"10:00",取决于当天是不是夏令时。
原文作者提醒:比较时间用UTC,显示时间用本地——但永远让用户知道你在用哪个时区。CET还是CEST?写清楚,别让人猜。
还有个更隐蔽的坑:时区数据库更新。IANA时区库每年变好几次,某个国家突然宣布取消夏令时,你的旧数据可能永久错位。依赖系统时区库的代码,本质是借债。
最安全的做法?把时区规则和业务数据一起存。重算历史事件时,用当时的规则,不是现在的。
作者写这篇文章时是2026年3月24日,正卡在DST Gap里。这种窗口期每年出现两次——3月北美先切、欧洲跟上;10月欧洲先退、北美殿后。中间几周,跨大西洋的会议安排全是雷区。
你的日历插件、倒计时组件、预约系统,有没有硬编码过"纽约-伦敦=5小时"?现在它是6小时。不是bug,是大陆级别的异步。
下次测试时,把系统时间调到3月15日,看看你的app会不会把伦敦用户约到错误的会议室。
热门跟贴