在印度用 Docker 起 Postgres,容器时区差半小时让我多查了两小时
This post is available in 简体中文 only — the original follows.
上个月在孟买一台测试机上复现客户的问题,环境是 Ubuntu 22.04,Docker 24.x,Postgres 15.4 官方镜像,数据量不大,一张订单表 80 万行左右,但每条记录都带 created_at。现象很怪:后端写进去的时间是对的,客户从后台导出 CSV 看到的时间总比实际早 30 分钟,而且只有一部分行错,不是全部。
先确认了不是前端展示的问题,直接连库查:
SELECT now(), current_setting('TimeZone');
-- 2024-05-21 10:12:33+05:30 | Etc/UTC
容器里是 UTC,宿主机是 Asia/Kolkata。也就是说,Django 那边按 UTC 存,导出脚本如果拿本地时间比较,就会在 5 小时 30 分这个偏移上出错。我先在 compose 里把时区固定住:
services:
db:
image: postgres:15.4
environment:
TZ: Asia/Kolkata
PGTZ: Asia/Kolkata
volumes:
- ./pgdata:/var/lib/postgresql/data
然后进容器验证:
docker exec -it db bash -c "date && psql -U postgres -c 'show timezone;'"
输出是 IST 和 Asia/Kolkata,问题消失。但这也暴露了另一件事:如果已有数据是按 UTC 写进去的,改时区不会自动转换那些 timestamp 值,只影响新写入和 now() 的显示。对已有 80 万行,我是写了个迁移脚本,按业务上约定的“所有历史时间都是 UTC”统一转成 timestamptz 再转回来,而不是直接改列类型,避免被隐式转换坑到。
这么做代价是容器启动时多了一次时区文件加载,基本可以忽略;真正麻烦的是团队里有人本地用 macOS 跑容器,TZ 变量行为不完全一致,最后还是把导出逻辑改成显式 AT TIME ZONE 'Asia/Kolkata' 更稳。
边界条件也说一下:如果数据链路里还有 Kafka 或外部 API 传 epoch 秒,容器时区根本管不到,必须在应用层统一。另外 Postgres 的 timestamp without time zone 列不会因为改 TZ 而改变存储值,这点我踩过,白白多查了两小时。
你们在印度环境里是让数据库跟着本地区时区走,还是坚持全链路 UTC、只在展示层转?
0 comments
No comments yet — be the first.