DB时区是根据SQL连接确认,还是pgsql里面的配置?如果我连接的时候没有定义timesize,那么pgsql是取自己配置项吗?这个配置项在哪里?如果这个配置项被注释了,是不是取服务器时区
1. 优先级顺序:谁决定了当前的时区?
PostgreSQL 确定时区的顺序如下(前者覆盖后者):
- SQL 连接会话 (Session):你在 Go 的 DSN 中定义的
timezone=UTC或连接后执行的SET TIME ZONE。 - 用户/数据库设置:针对特定用户或数据库执行过
ALTER ROLE ... SET timezone或ALTER DATABASE ... SET timezone。 - 配置文件 (
postgresql.conf):里面的timezone参数。 - 操作系统 (OS) 时区:如果配置文件里没写或被注释了,PostgreSQL 会询问操作系统。
2. 回答你的具体问题
Q:DB 时区是根据 SQL 连接确认,还是 pgsql 里面的配置?
答:两者都有。
- 配置决定了"默认值"。
- 连接决定了"当前值"。
如果你在 Go 连接字符串里定义了timezone=UTC,那么该连接会覆盖数据库的所有默认配置。
Q:如果连接时没有定义 timezone,是取自己配置项吗?配置项在哪里?
答:是的。
- 它会读取 PostgreSQL 数据目录下的
postgresql.conf文件。 - 在该文件中搜索
timezone关键字。通常你会看到类似timezone = 'Asia/Shanghai'这样的设置。
Q:如果这个配置项被注释了,是不是取服务器时区?
答:是的。
- 如果
postgresql.conf中没有timezone这一行(或者被#注释掉),PostgreSQL 会在启动时检查操作系统的环境变量(如TZ)或系统的时区文件(如 Linux 的/etc/localtime)。 - 风险提示:依赖服务器时区是危险的,因为一旦迁移服务器,数据库的行为可能会发生变化。
3. 为什么字段类型 timestamptz 和 函数 now() 的组合很安全?
即使你的配置乱七八糟(比如配置成了北京时间,连接没写时区),timestamptz 依然能保证数据的绝对准确性:
- 执行
now():数据库产生一个带时区的时间戳(比如2023-10-27 10:00:00+08)。 - 存储到
timestamptz:PostgreSQL 内部强制将其转换为2023-10-27 02:00:00+00(UTC) 存入磁盘。 - 读取:当你以后用
timezone=UTC的 Go 程序去读时,它会准确地返回 UTC 时间,不会因为当初存入时的本地时区而产生偏移。
调研建议
为了确保环境的一致性,最稳妥的做法是:
- 数据库容器/服务器:在
postgresql.conf或 Docker 环境变量中显式指定TZ=UTC。 - Go 代码:在 DSN 中显式指定
timezone=UTC。
这样即使操作系统时区被意外修改,你的业务数据也永远是标准的 UTC。