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

前几天写了个小脚本,定时给群友发活动提醒,逻辑贼简单,本地先转成utc存库,到点再转回本地发我寻思这还能出啥事。离谱

结果活动晚上八点开始,有人七点就收到,有人九点才收到,还有哥们直接凌晨收到把我骂醒。我当场懵了。
绝了
查了半天才发现,我开发机时区是东八区没错,但容器里默认跑的是UTC,我那句转utc其实啥也没转,等于拿错基准算了一圈。数据库里的时间戳看着都对,落到一个根本不知道自己时区的环境里全乱套。

最绝的是,本地测了三天都没复现,因为开发机时区是配好的。啪一下扔服务器就翻车。

现在我的原则就一条:时间一律存utc时间戳,显示层再转,容器启动第一件事先设TZ。别信任何"本地时间",服务器压根不知道自己在地球哪个角落。哈哈哈这坑踩一次记一辈子。

lol2006
[链接]

前几年困国外大半年才叫真背刺,国内凌晨给我妈打视频,她以为出啥大事了。服务器好歹不用挨骂哈哈

radar
[链接]

这坑踩得我隔着屏幕都替你头皮发麻。不过你们知道吗,我第一反应是——你那容器到底谁搭的?默认UTC这事我怎么听说的版本不一样,我们组之前有次也是,运维图省事直接用的基础镜像,全组定时任务集体慢八小时。我怀疑你这不是自己忘设TZ,是镜像里压根被动过手脚。卧槽话说你开发机时区是"配好的",谁给你配的?6该不会也是同一个人顺手埋的雷吧,我嗅到瓜味了。

skeptic__owl
[链接]

容器默认UTC这坑太经典了,简直是新人必修课。我当年也在这栽过,本地跑得好好的,一上线全乱套,时差搞得人头秃。现在看到时间处理就条件反射想设TZ,C’est la vie.

stack
[链接]

Dockerfile里加一行 ENV TZ=Australia/Sydney 比启动脚本设TZ稳,后者偶尔会被entrypoint覆盖掉。存库用UTC时间戳没问题,但显示层转换别自己写,直接用带IANA时区ID的库处理夏令时,不然换季那天还得被背刺一次。

dev_2001
[链接]

TZ环境变量能兜底,但只靠它还不够稳。

容器里设TZ=Asia/Shanghai确实能解决大部分问题,但这本质上还是把环境配置和代码逻辑绑死了。换个思路:代码里压根别碰本地时间这个概念。

存库用UTC Unix timestamp(整型),或者带时区信息的ISO 8601字符串。展示层再根据用户自己的时区去转。注意是“用户的时区”,不是“服务器的时区”。你群里那个凌晨收到消息的哥们,他的客户端可能就在另一个时区,这时候拿服务器所在地的时间去算,怎么算都是错的。

Dockerfile里加一行ENV TZ=UTC是个好习惯,强制所有容器统一基准线,避免不同服务之间因为时区不一致互相打架。但更彻底的做法是在语言层面掐断隐患。比如Python,处理时间一律用datetime.now(timezone.utc),别用裸的datetime.now()。Java用Instant。Go用time.Now().UTC()。从源头上让“获取本地时间”这件事变得麻烦,开发者自然就会选对的路径。简单说

还有个容易漏掉的坑:夏令时(DST)。如果你这脚本以后要给海外群友发提醒,光存个“东八区晚上八点”是会出事的。每年切夏令时那几天,同一个本地时间会凭空多出一小时或少一小时。这也是为什么强调存UTC绝对时间戳——UTC没有夏令时,物理规律不变,变的只是人类怎么读表。

本地测了三天没复现这事太典型了。开发机和生产环境不一致是万恶之源。建议把时区检查加到CI/CD的health check里,启动时打印一下当前环境的时区和偏移量,不对直接报错退出,别让它带着错配置跑起来再去祸害用户。

顺便问一句,你这定时任务用的cron还是自己写的sleep循环?如果是cron,容器里的crond默认也是按UTC跑的,这里还得单独配一次。

profive
[链接]

“时间一律存UTC时间戳”这个原则在工程实践中基本是共识,但具体到“显示层再转”这一步,其实有不少值得商榷的细节。

楼主踩的容器时区坑很典型。根据Docker官方文档,基础镜像默认不带TZ环境变量,如果不显式配置,date命令返回的就是UTC。这在微服务架构里几乎是必考题。之前看过一份内部统计,某团队上线首月37%的时间相关bug都源于开发环境和生产环境的时区不一致。

不过关于存储策略,想补充一点:存UTC时间戳(比如Unix epoch)对事件排序和跨时区计算确实最优,但如果业务涉及“未来某个本地时间点”,纯UTC可能会出问题。原因是夏令时。

举个例子,用户预约了纽约时间2024年11月3日凌晨1:30的提醒。那天正好是北美夏令时结束的日子,凌晨1点到2点会重复出现一次。嗯如果只存转换后的UTC时间戳,系统无法区分用户指的是第一个1:30还是第二个。IANA Time Zone Database每年更新多次,就是为了处理这类边界情况。

所以更严谨的做法可能是分层存储:记录事件发生的绝对时刻用UTC时间戳;但如果是用户设定的未来计划,最好同时保留原始输入(如"America/New_York"时区标识加上本地时间字符串)。这样即使IANA规则库更新了,重新计算也不会丢精度。

另外couch2003之前好像也提过类似的问题?前端展示层的时区转换,建议直接依赖Intl API或者成熟的库,别自己算偏移量。手动加减8小时这种操作,看着简单,遇到历史时区变更记录就会翻车。

话说回来,被群友凌晨骂醒这种事,经历一次大概比看十篇最佳实践都管用… 你那个脚本后来怎么改的,直接上cron加环境变量了?

stone_773
[链接]

"本地能跑"这四个字害了多少人。说实话

我以前也踩过类似的坑,不是时区,是编码。开发机中文好好的,一上服务器全变问号,折腾一整夜才发现locale没配。那会儿刚毕业,觉得代码逻辑对了就万事大吉,哪知道运行环境自己就是个变量。

你总结的原则挺好,不过我觉得可以再加半条——写进文档里。不然下一个接手的人看到一堆UTC时间戳,不一定知道你当初为什么这么干,搞不好又绕一圈。

踩一次记一辈子挺好,就是别忘了顺手写个注释,给后面的人省点头发。

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