PostgreSQL中计算两日期天数差应优先用减法(-),返回整数天数,支持排序和聚合;age()返回interval类型,按月/日分段,不适合数值运算。

PostgreSQL 中计算两个日期相差天数,优先用日期减法(-),而不是 age();后者返回的是“年龄式间隔”,不能直接用于数值比较或聚合。
用 - 减法直接得到整数天数
PostgreSQL 对 DATE 类型做减法会自动返回以天为单位的 integer,干净、可排序、可参与数学运算:
-
DATE '2024-05-10' - DATE '2024-05-01'→ 返回9 - 支持
TIMESTAMP,但结果是double precision(含小数秒),如需整数天,建议先截断到日:(t1::date - t2::date) - 顺序很重要:前减后为正,后减前为负;不满足“绝对差”时记得套
ABS() - 兼容性好,所有 PostgreSQL 版本都支持,且索引可生效(若字段有 B-tree 索引,
WHERE date_col - '2024-01-01' > 30可能走索引)
age() 返回的是 interval,不是天数
age() 设计目标是“人类可读的年龄”,比如 age('2024-05-10', '2023-06-15') 返回 10 mons 25 days —— 它按月/日/年分段处理,不等于简单日差:
-
age('2024-03-01', '2024-02-01')→1 mon(31 天?28 天?取决于当月),无法直接转成统一“天” -
age()结果是interval类型,不能直接GROUP BY或AVG();强行EXTRACT(day FROM age(...))只取“日部分”,会丢失月份影响(例如 1 mon 2 days 里只取 2) - 仅适合展示场景,比如生成报表中的“X years Y months Z days”文本
需要带时区或跨 DST 的精确天数?仍用减法,但注意类型转换
如果字段是 timestamptz,直接相减得到的是带时区偏移的 interval,此时别依赖 age(),而是标准化到 UTC 或日期再算:
- 要“自然日差”(忽略时间、只看日期):
(ts1::date - ts2::date) - 要“精确经过的 24 小时周期数”:
FLOOR(EXTRACT(epoch FROM (ts1 - ts2)) / 86400) -
age()在夏令时切换日附近行为不稳定(比如从 2AM 跳到 3AM,age()可能少算 1 小时),而减法基于绝对时间戳,更可控
真正要小心的是隐式类型转换:把字符串直接丢进 age('2024-01-01', '2024-02-01') 没问题,但若其中一个是 text 字段没显式转 DATE,可能触发意外 cast 规则或报错。写死常量时加 ::date 更稳妥。

















