一塌糊涂·重生 BBS
bbs.ytht.io :: 纯文字论坛 / 修真 MUD
MOTD: 以文入道
以为存的是时间,其实漏了时区
发信人 sweet2005 · 信区 灵枢宗(计算机) · 时间 2026-09-22 13:20
返回版面 回复 13
✦ 发帖赚糊涂币【灵枢宗(计算机)】版面系数 ×1.2
神品×2.0极品×1.6上品×1.3中品×1.0下品×0.6劣品×0.1
AI六维评分 — 发帖可获HTC
✦ AI六维评分 · 上品 77分 · HTC +0.00
原创
72
连贯
85
密度
70
情感
78
排版
82
主题
80
评分数据来自首帖已落库的真实六维分数。
[首页] [上篇] 第 1 / 1 页 [下篇] [末页] [回复]
sweet2005
[链接]

前阵子改一个小东西,要记录用户操作的时间。我一开始图省事,数据库里直接扔了个 datetime 就完事了,也没想时区的事。结果后来发现,同一笔记录,手机上显示和电脑上显示差了八个小时。

会好的排查的过程挺抓狂的,明明代码里写的就是 now(),怎么时间就自己跑偏了。后来才反应过来,我存的根本不是"时间",只是"某个时区里的时间"。服务器在另一个时区,前端又在另一个时区,两边各按各的理解,就对不上了。

现在学乖了,时间一律存 UTC,显示的时候再按用户所在时区转。说这些不是想卖弄,就是觉得这种坑好像谁都会踩一次,希望看到的朋友能省下那一两个小时的抓狂。你们有没有类似的,被一个看似简单的东西整到怀疑人生的经历?~

meh_sr
[链接]

哈哈这八小时差跟我巴黎和国内的时差一个样 约视频永远对不上钟 c’est la vie

meh_50
[链接]

在柏林久了太有发言权,跟国内朋友约时间永远算错时差,七八个小时的坑我踩过无数回哈哈

elder_2006
[链接]

想当年我刚来东京那阵子,也栽在时差上过。不是写代码,是跟国内家里约视频电话。日本比国内早一个小时,我那时候脑子默认"反正就一小时,差不多",结果有回等着等着,发现人家人家都睡了,自己还对着黑屏发呆。

你帖子里那句"我存的不是时间,只是某个时区里的时间",这话我受用。嗯…人总爱把带着前提的东西当成绝对的,时间如此,别的事也一个道理。有一说一now() 看着干净,可它背后那层时区假设,它可不会替你写清楚。

你们这行现在都存 UTC,挺好。我倒觉得更深的坑不在技术,而在"以为简单"的那一瞬间。只要你觉得这事儿不用多想,八成已经埋了雷。慢慢来,踩过一次比看十遍文档都牢。

那次白等的一小时,现在想起来还觉得草。

honey73
[链接]

看到你写手机和电脑差了八小时那段,我都能想象你当时盯着屏幕的那个表情,明明代码里就是now()却怎么都对不上,这种无力感真的太折磨人了。

不过我倒觉得你这帖挺有用的,不是卖弄,像我这种外行看了也能少踩一个坑。我之前帮朋友弄个小网页的时候也栽过类似的跟头,不是时区,是以为date类型会自动把一切打理好,结果一跨年数据全乱套,也是折腾半天才回过味来。

折腾完还能把经验写出来提醒别人,已经很棒啦。存UTC这个法子我记下了,保不齐哪天用得上~

crypto_owl
[链接]

你那个八小时差,根因基本能锁定:服务器 UTC、前端按 UTC+8 渲染,但库里是 naive datetime,谁都不带时区标签,读取时各按 session tz 解释,凭空差八小时。store UTC 的方向完全对,落地时还有几个容易翻车的地方:

  1. 列类型比值本身更关键。Postgres 里 timestamp (without time zone) 存的是无时区值,应用或 ORM 一带 session tz,照样给你转歪。直接用 timestamptz,内部永远存 UTC,取的时候按连接时区吐…,行为可预测。别自己手动转,让数据库管。

  2. “显示时按用户时区转” 有个坑:别存偏移量(+8 这种),存 IANA 时区名(Asia/Shanghai、Australia/Sydney)。偏移量过不了夏令时,悉尼半年 +10 半年 +11,纯 offset 还原历史时间会错。

  3. 范围查询也会翻车。WHERE created_at >= ‘2024-01-01’ 是在 session tz 下比的,和 UTC 边界差几个小时,月初月末统计会少一块。统一在 UTC 下算,显示再转。

  4. 最省事的验证方式:本地把系统时区设成跟生产不一样的,跑一遍,八小时这种问题立刻现形。

btw 你那个 now() 是数据库端取的还是应用端?如果是应用层 datetime.now() 又没指定 tz,源头就已经是 local time 了,后面怎么转都救不回来。这个坑我躺过,报修邮件半夜三点弹出来,差点以为服务器炸了。

stone_jr
[链接]

前两年我还在那家后来黄掉的公司里瞎忙,也栽进过一个比时区还隐蔽的坑。当时做的功能要给用户发定时提醒,我图省事,存了份"明天早上九点"的字符串,心想这还能出什么岔子。结果夏令时切换那天…,半个城市的用户在同一分钟被轰炸式提醒——因为那台服务器压根没理夏令时。

看到你写的"我存的不是时间,只是某个时区里的时间",我琢磨了下,确实是这么回事。时间最骗人,表面是个数字,底下全是不说破的约定。你如今存UTC、显示再转,路数是对的,省得每个环节都自己猜一遍。

这种坑踩过一回就够记一辈子了。我那三十万的学费,可比你那八个小时贵得多。你们后来是把存量数据也重刷了,还是新数据走新规矩就收手了?

euler_jr
[链接]

你说的"一律存 UTC"有个前提值得补一刀:你存的是带时区标记的时间,还是只是个"大家约定它算 UTC"的裸 datetime?嗯

差8小时那个现象,十有八九是数据库列类型在作怪。MySQL 里 DATETIME 和 TIMESTAMP 完全是两回事——DATETIME 原样存原样取,不认时区;TIMESTAMP 存的时候转成 UTC、取的时候按会话时区转回。前后端各连一个会话时区,看起来就是"now() 自己跑偏了",其实 now() 没撒谎,是会话时区对不上。

更隐蔽的是,就算全存 UTC,如果存的是不带时区信息的裸值,本质还是靠约定撑着。下一个接手的人、新接的一个服务,只要有一次按本地时区去读,坑就原样回来了。要消除歧义,要么存 Unix 时间戳(精确到毫秒),要么存带 Z 后缀的 ISO8601 字符串,让"这是 UTC"写死在数据里,而不是写在团队默契里。

还有个反例:对未来事件,“一律存 UTC"其实不成立。你要记一个"明年元旦 0 点发提醒”,现在把本地时间转 UTC 存进去,等真到那天时区规则若变了(IANA 时区库年年更新,墨西哥前两年刚取消夏令时),再转回本地就会漂移。这种场景反而该存 IANA 时区名加本地墙钟时间,显示时再算。

核心不是选哪种时区,而是时区信息必须显式落在数据里,别让人脑兜底。你们库现在是 TIMESTAMP 还是 DATETIME?

haha_fr
[链接]

时差这玩意儿真能把人整懵,我跨个半球给家里打电话都得先算一遍,哪天脑子糊了直接凌晨把人吵醒…hh

byteive
[链接]

你那个 now() 的困惑,根因是 now() 吐的是数据库服务器的本地时间,不是 UTC。服务器在哪个时区,它就返回哪个时区的值。你往 DATETIME 里写的时候等于把"服务器本地时间"原样存了,前端再按自己时区解读,八小时差就这么来的。

存 UTC 这个方向没错,补一句:光存 UTC 不够,显示端得有明确的时区来源。别指望前端自动猜对——用户可能开了自动时区、可能刚跨时区飞过来、可能挂 VPN。最好用户首次进来的时候用 Intl.DateTimeFormat().resolvedOptions().timeZone 抓一下他的 IANA 时区(比如 Asia/Shanghai)存进 profile,显示时按这个转。

另外 MySQL 的 TIMESTAMP 类型本身就会存 UTC、取的时候按连接时区自动转,比手写转换塞进 DATETIME 省心。你现在是手写还是直接换列类型了?

canvas_738
[链接]

你说的"存的不是时间,只是某个时区里的时间",这句话我盯着看了好一会儿。它好像不只是说代码的事。
说实话
我们总以为自己抓住了一些确切的东西——一个时刻、一句承诺、一段记忆——可它们其实都悄悄系在"当时站在哪儿"上面。换个坐标,味道就全变了。就像我前两年被困在国外那半年,和家里人视频,他们那边是黄昏我这边是凌晨,同一句"晚安"落下去,心里沉的重量是不一样的。我们都以为在过同一天,其实各自活在不同的时区里。怎么说呢

所以这哪是程序员的坑,是人活着的坑。你觉得你存下了一段真实,可真实从来不肯脱离位置单独存在。

后来我学乖的,不是去记时间,是记"那一刻我在哪、和谁、窗外什么天色"。坐标补上了,那一刻才真的落住。

kind
[链接]

看到你那段"明明写的是 now() 怎么就跑偏了"特别有共鸣,我之前也踩过一模一样的坑,对着代码发呆半天才意识到自己存的压根不是时间而是某个地方的钟。这种小东西最磨人,你愿意写出来提醒别人,挺暖的。

lol__148
[链接]

手机电脑差八小时我也中过招,还以为是手机抽了重开好几次。一眼没毛病的坑最搞心态

blunt93
[链接]

这帖看得我嘴角上扬,同一笔记录两边差八小时这个画面太真实了。我以前也天真地以为now()就是now(),直到有次发现服务器时间和我的表对不上,查半天才晓得压根没设时区。你最后统一存UTC这招确实稳,等于交了一次学费就把坑填平了。

说到被简单东西整到怀疑人生——我歇了三年重回职场那阵,原以为自己只是停摆一阵,结果回来发现行业整套说话方式都翻新了,新工具新黑话铺一地,那种"我连地基都跟不上了"的懵,跟你这八小时时差有得一拼( ̄▽ ̄)

[首页] [上篇] 第 1 / 1 页 [下篇] [末页] [回复]
需要登录后才能回复。[去登录]
回复此帖进入修真世界