MySQL的DATEDIFF只返回整数天数,忽略时间部分;需小时或秒级精度应改用TIMESTAMPDIFF;PostgreSQL通过timestamp相减得interval;SQL Server的DATEDIFF按边界计数而非精确时长。

MySQL里DATEDIFF只算天数,别指望它返回小时或秒
MySQL 的 DATEDIFF 函数只接受两个 DATE 类型值(或能自动转为日期的字符串),结果永远是整数天数,忽略时间部分。比如 DATEDIFF('2024-01-01 23:59:59', '2023-12-31 00:00:01') 返回 1,不是 1.999 或 47 小时。
常见错误现象:用 DATEDIFF 计算订单处理耗时、用户在线时长,结果全是 0 或跳变整数,完全失真。
- 要算小时差,改用
TIMESTAMPDIFF(HOUR, start_time, end_time) - 要算秒级精度,必须用
TIMESTAMPDIFF(SECOND, start_time, end_time),且字段类型得是DATETIME或TIMESTAMP - 注意参数顺序:
TIMESTAMPDIFF是TIMESTAMPDIFF(unit, start, end),和DATEDIFF(end, start)的顺序相反
PostgreSQL没有DATEDIFF,但interval运算更直接
PostgreSQL 不提供 DATEDIFF,但两个 TIMESTAMP 相减直接得到 INTERVAL 类型,比如 '2024-01-01 14:30'::TIMESTAMP - '2024-01-01 10:15'::TIMESTAMP 返回 04:15:00。
使用场景:日志分析中计算请求响应间隔、任务执行时长,不需要函数包装就能拿到结构化时长。
- 提取天数用
(end_time - start_time) / INTERVAL '1 day'(结果是 numeric) - 提取总秒数用
EXTRACT(EPOCH FROM (end_time - start_time)),返回浮点数,适合后续数学运算 - 别写
AGE(end_time, start_time)来“模拟” DATEDIFF——AGE是带年月日拆分的逆向函数,用于显示人类可读年龄,不适合数值计算
SQL Server的DATEDIFF单位陷阱最多
SQL Server 的 DATEDIFF 看似灵活,但单位是“边界跨越次数”,不是精确时长。例如 DATEDIFF(MINUTE, '2024-01-01 10:00:59', '2024-01-01 10:01:01') 返回 1,哪怕只差 2 秒——因为跨过了一个分钟边界。
性能影响:用 DATEDIFF 做 WHERE 条件(如 DATEDIFF(DAY, created_at, GETDATE()) > 7)无法走索引,因为函数作用于列;应改写为范围查询:created_at 。
- 想算真实秒数差,优先用
DATEDIFF(SECOND, start, end),但要注意溢出(超过 24 天会超 int 范围) - 大跨度计算建议用
DATEDIFF_BIG(SQL Server 2016+),支持 bigint 返回值 - 避免用
MONTH或YEAR单位做业务逻辑判断——12 月 31 日到次年 1 月 1 日,DATEDIFF(YEAR, ...)就是 1,实际才过 1 天
跨数据库写法怎么尽量不翻车
没有银弹函数能通吃所有数据库,但可以绕开 DATEDIFF 自身缺陷,用底层时间戳做统一处理。
容易被忽略的点:不同数据库对 NULL 的处理一致,但对非法日期字符串容忍度不同(MySQL 可能静默转成 0000-00-00,PostgreSQL 直接报错 invalid input syntax for type timestamp)。
- 最稳的通用写法是:把时间转成 Unix 时间戳(秒数),再相减。MySQL 用
UNIX_TIMESTAMP(ts),PostgreSQL 用EXTRACT(EPOCH FROM ts),SQL Server 用DATEDIFF(SECOND, '1970-01-01', ts) - 如果必须用
DATEDIFF类函数,先确认目标数据库是否支持所需单位,再检查字段是否含时区信息——带时区的TIMESTAMPTZ在 PostgreSQL 中参与运算会自动转 UTC,而 SQL Server 的DATETIMEOFFSET需显式用SWITCHOFFSET - 上线前务必在真实数据上验证边界值:零点、闰秒附近、跨年/跨月第一天,这些地方
DATEDIFF行为最容易出人意料

















