DEBUG.WIKI
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →

PostgreSQL to_char 把分钟显示成了月份

时间模板中的 MM 表示月份,MI 才是分钟。修正分钟位置,并分开核对小时制、时区转换与格式化文本的含义。

PostgreSQL 时间列显示 14:31:04,用 to_char(..., 'YYYY/MM/DD HH24:MM:SS') 格式化后却变成 14:08:04。日期是八月,而分钟位置也变成了 08,这时应检查模板里的第二个 MM。

在 PostgreSQL 的日期时间模板中,MM 表示月份,MI 才表示分钟。两者都是合法模式,所以写错后通常不会报语法错误,只会得到错误的展示文本。

只修改分钟位置的模式

下面的只读示例使用固定时间,不需要访问业务表,也不受当前时间推进影响:

SELECT to_char(timestamp '2026-08-02 14:31:04',
               'YYYY/MM/DD HH24:MM:SS') AS wrong_text,
       to_char(timestamp '2026-08-02 14:31:04',
               'YYYY/MM/DD HH24:MI:SS') AS corrected_text;

按模板规则,第一列应得到 2026/08/02 14:08:04,第二列才是 2026/08/02 14:31:04。日期部分的 MM 仍应保留;不要把整条格式串里的月份也一并替换成 MI。

常用的 24 小时显示组合为 HH24:MI:SS。HH、HH12 则按 12 小时计,若需要区分上午下午还要表达对应信息。不同语言和格式化库的模式不通用,不能把应用侧的一条日期格式原样搬进 SQL 后,仅凭长得相似判断含义。

真实查询可调整为:

SELECT id,
       started_at,
       to_char(started_at, 'YYYY/MM/DD HH24:MI:SS') AS display_time
FROM job_runs
WHERE id = 20;

job_runs、列名和编号是占位值。保留原列一起查询,便于对比原始值与展示文本;不要为了修正显示结果执行 UPDATE 重写时间。

去掉时区文字,不等于转换到指定时区

to_char() 返回 text。格式串没有时区模式,只表示结果文本不打印偏移或时区,并不会把时间自动变成 UTC,也不会修改原字段类型。

若 started_at 是 timestamp with time zone,还要明确展示所用时区。需要固定以 UTC 展示时,可以在表达式中明确转换:

SELECT to_char(
           timestamptz '2026-08-02 14:31:04-07' AT TIME ZONE 'UTC',
           'YYYY/MM/DD HH24:MI:SS'
       ) AS utc_text;

这个示例应显示 2026/08/02 21:31:04。它与 14:31:04 的小时差是时区换算,与错误使用 MM 导致分钟等于月份不是同一个问题。输出文本本身不含偏移,因此接口或列名必须明确这是 UTC,不要让接收端自行猜测。

AT TIME ZONE 对不同输入类型有不同方向:上述写法把带时区时间转换为指定时区的无时区本地时间表示。原列若是 timestamp without time zone,使用同一运算符是在给它解释时区含义,不能不检查类型就照搬。

用月份与分钟不同的数据验收

选择月份与分钟明显不同的样本,例如八月的 31 分钟;也检查整点和接近一小时末尾的值。若测试数据恰好是八月的 08 分钟,错误模板可能看起来完全正常。

继续核对小时制、时区和秒的小数精度。SS 只打印整秒,模板没有显示的部分并不代表原值不存在。不要把格式化文本替代原始时间字段进行后续时间运算,除非下游协议确实要求文本。

修复范围通常是查询或报表的格式串。保留原版本,验收输出列类型和下游解析约定;需要回退时恢复展示表达式,不改业务时间数据。如果错误文本已经导出,还需重新生成相应文件,改 SQL 不会自动修正旧产物。