DATEDIFF函数计算天数存在误差,根本原因是它计算的是跨越指定单位边界的次数而非实际经过时间,SQL Server按午夜线、MySQL截断时间部分、PostgreSQL需用epoch提取秒数并换算,跨时区或夏令时场景必须统一转UTC再计算。

DATEDIFF 函数计算天数存在误差,根本原因不是它“算错了”,而是它压根就没打算算你理解的“两个时间点之间相隔多少天”——它算的是“跨越了多少个指定单位边界”。
SQL Server 的 DATEDIFF(day, ) 算的是午夜线穿越次数
比如 DATEDIFF(day, '2024-01-01 23:59:59', '2024-01-02 00:00:01') 返回 1,只因跨过了 00:00 这条日边界;而 '2024-01-01 00:00:00' 到 '2024-01-01 23:59:59' 却返回 0,哪怕差了近一整天。
- 它不看具体秒数,只看日期部分是否变化
- 想得精确天数(含小数),必须用
DATEDIFF(second, start, end) / 86400.0或DATEDIFF(millisecond, start, end) / 86400000.0 - 单位越小(如
second),结果越接近真实经过时间
MySQL 的 DATEDIFF(end, start) 强制截断时间部分
无论你传入 '2024-01-01 15:30:00' 还是 '2024-01-01 23:59:59',DATEDIFF() 都先转成 DATE 类型再算,等价于 DATEDIFF(DATE('2024-01-01 15:30:00'), DATE('2024-01-02 01:00:00')) → -1。
- 参数顺序是
DATEDIFF(end_date, start_date),反了就是负值 - 要保留时间精度,改用
TIMESTAMPDIFF(second, start, end) / 86400.0 - 字段是
DATETIME时,别直接塞进DATEDIFF(),先确认业务是否真能接受“丢掉时分秒”
PostgreSQL 根本没有 DATEDIFF,但减法也容易误解
PostgreSQL 不提供 DATEDIFF,常用 end_ts - start_ts,结果是 interval 类型。但 EXTRACT(day FROM interval) 只取“日”字段,不累计小时;比如 '2 days 25:00:00'::interval 的 day 字段仍是 2,不是 3.04。
- 要真正精确天数(含小数),必须用
EXTRACT(epoch FROM (end_ts - start_ts)) / 86400.0 - 两个
DATE相减(end_date::DATE - start_date::DATE)才返回整数天,安全可靠 - 若字段是
TIMESTAMP WITH TIME ZONE,务必先统一时区(如AT TIME ZONE 'UTC'),否则夏令时跳变会引入误差
最常被忽略的一点:所有数据库里,只要涉及跨时区、夏令时或高精度业务(比如计费、SLA),DATEDIFF 或简单减法都不可信——必须先把时间转成 UTC 再算,否则凌晨拨钟那1小时,就足以让结果偏移一整天。

















