如何让PostgreSQL默认存储UTC时间戳?
你遇到的问题根源在于默认值的类型不匹配:
你定义的(now() at time zone('utc'))返回的是无时区的TIMESTAMP类型(仅表示UTC时间点的原始数值),而字段是TIMESTAMP WITH TIME ZONE(简称timestamptz)。当PostgreSQL将无时区时间插入timestamptz字段时,会默认用当前会话时区解释该时间,再转换为UTC存储——这会导致最终存储的时间偏离预期的UTC时间,查询时也会按会话时区显示本地偏移。
要让字段默认存储带UTC偏移的timestamptz值,需确保默认值本身就是带UTC时区的timestamptz类型,以下是几种可行写法:
双重
AT TIME ZONE转换created_at TIMESTAMP WITH TIME ZONE DEFAULT (now() AT TIME ZONE 'utc') AT TIME ZONE 'utc'原理:第一次
AT TIME ZONE 'utc'将now()(带时区)转为无时区的UTC时间;第二次AT TIME ZONE 'utc'明确告知PostgreSQL该无时区时间属于UTC时区,最终生成带UTC偏移的timestamptz值。基于
utc_timestamp函数转换created_at TIMESTAMP WITH TIME ZONE DEFAULT utc_timestamp AT TIME ZONE 'utc'原理:
utc_timestamp直接返回当前UTC时间的无时区值,再通过AT TIME ZONE 'utc'转换为带UTC偏移的timestamptz。直接构造UTC时间戳
created_at TIMESTAMP WITH TIME ZONE DEFAULT TIMESTAMP WITH TIME ZONE 'epoch' + EXTRACT(EPOCH FROM now()) * INTERVAL '1 second'原理:通过
now()获取当前时间的epoch秒数,结合epoch起始时间直接生成带UTC偏移的timestamptz值。
补充说明
PostgreSQL的timestamptz内部实际存储UTC时间戳,显示时会根据会话timezone参数转换为对应时区时间。若希望查询默认显示UTC时间,可设置会话时区:
SET TIME ZONE 'utc';
或查询时指定转换:
SELECT created_at AT TIME ZONE 'utc' FROM your_table;
内容的提问来源于stack exchange,提问作者SinxroFozotron

