活动开始时间存的是 2026-03-01 10:00:00,应用容器 TZ 从 UTC 改成 Asia/Shanghai 后,页面显示成 18:00,报名入口提前八小时关闭。第一次遇到会往复杂处想,其实漏掉的多是个小前提。

ALTER TABLE events ALTER COLUMN starts_at TYPE timestamptz
  USING starts_at AT TIME ZONE 'Asia/Shanghai';
SHOW TimeZone;

timestamp without time zone 只存字面量,不带偏移,驱动读出时按会话时区解释。会话时区一变,同一个值就对应到另一个绝对时刻,历史数据也跟着一起漂。这一点先确认清楚,后面就不用反复试。

碰到「timestamp without time zone」这类问题,我习惯先把当前配置原样备份一份,改坏了立刻换回来,不用现场推。把这次用到的命令存进笔记,比记住结论有用,换个环境还能照着走。

改完隔一天再看一次,当场正常不代表能稳住。测试环境和线上的差别,往往就在版本号和那几行被忽略的配置上。

具体做法是,新表统一用 timestamptz 存绝对时间;已有列做一次迁移 按当时的业务时区补齐偏移;连接串里显式写 TimeZone 别依赖服务器默认;展示层统一定义用户时区 别在 SQL 里临时转换。

改完照着核一遍,把容器 TZ 改回 UTC 再打开页面 活动开始时间仍然是 10:00 报名入口不再提前关闭。

作者 9823189