MySQL的DATEDIFF仅支持天数差,会截断时间部分;SQL Server的DATEDIFF支持多种单位但需正确指定参数;PostgreSQL无该函数,需用减法或EXTRACT。

MySQL 的 DATEDIFF 只支持天数差,别想用它算小时或秒
DATEDIFF 在 MySQL 中只接受两个 DATE 或能自动转成日期的值(比如 '2024-03-15' 或 DATE(NOW())),返回整数天数。它会直接截断时间部分——DATEDIFF('2024-03-15 14:30:00', '2024-03-14 23:59:59') 结果是 1,不是 0,更不会告诉你差了 14 小时 30 分。
常见错误现象:DATEDIFF 返回意外的 0 或 1,尤其在对比同一天不同时间点时;或者误以为它能处理 TIMESTAMP 精度,结果丢失全部时间信息。
- 如果要算小时、分钟、秒,请改用
TIMESTAMPDIFF,并明确指定单位(如TIMESTAMPDIFF(HOUR, start_time, end_time)) -
DATEDIFF(a, b)永远等价于TO_DAYS(a) - TO_DAYS(b),底层就是按日历日做减法 - 注意时区:输入值若含时区偏移(如
'2024-03-15 10:00:00+08:00'),MySQL 会先转成会话时区再截日期,可能引发跨日偏差
SQL Server 的 DATEDIFF 单位参数必须写对,大小写不敏感但拼写不能错
SQL Server 的 DATEDIFF 功能强得多,支持 SECOND、MINUTE、HOUR、DAY、WEEK、MONTH、YEAR 等十多种单位,但第一个参数是单位名,不是字符串字面量——DATEDIFF('day', start, end) 会报错,正确写法是 DATEDIFF(day, start, end)(无引号)。
使用场景:判断订单是否超时(DATEDIFF(minute, created_at, GETDATE()) > 30)、统计用户上次登录距今多少周(DATEDIFF(week, last_login, GETDATE()))。
- 单位名不区分大小写,但拼写必须准确:
dd和day都行,但days或dy不行 - 结果是「边界跨越次数」,不是精确间隔:比如
DATEDIFF(MONTH, '2024-01-31', '2024-02-28')返回1(跨了 1 个“月边界”),哪怕实际只差 28 天 - 避免用
YEAR判断年龄,DATEDIFF(YEAR, '2000-12-31', '2024-01-01')得到24,但人还没过生日
PostgreSQL 没有 DATEDIFF,直接用减法或 AGE() 更自然
PostgreSQL 不提供 DATEDIFF 函数。日期/时间相减本身就有意义:end_time - start_time 返回 interval 类型(如 3 days 02:30:45),再用 EXTRACT 提取具体数值。
常见错误现象:照搬 MySQL 或 SQL Server 写法,直接敲 DATEDIFF(day, a, b),报错 function datediff(unknown, timestamp without time zone, timestamp without time zone) does not exist。
- 算天数差:用
(end_time::date - start_time::date)(转成 date 后相减,得整数天) - 保留时间精度:用
EXTRACT(EPOCH FROM (end_time - start_time)) / 3600算小时,或EXTRACT(DAY FROM (end_time - start_time))提取 interval 中的天数部分 - 需要可读性高的相对时间(如 “2 years 3 mons 5 days”)?用
AGE(end_time, start_time),但注意它是从大到小减(AGE(NOW(), created_at))
跨数据库写逻辑时,DATEDIFF 是最大兼容性陷阱之一
同一个函数名,在不同数据库里行为差异极大:MySQL 只认天、SQL Server 单位靠参数、PostgreSQL 根本没有。硬写 DATEDIFF 基本等于放弃移植性。
性能影响:MySQL 的 DATEDIFF 因为只比日期,可以走索引;但 SQL Server 的 DATEDIFF(day, col, GETDATE()) 会让 col 上的索引失效(函数包裹列),除非建计算列索引。
- 如果业务逻辑必须依赖日期差,优先在应用层计算(如 Python 的
(end - start).days或 JavaScript 的Math.floor((end - start) / (1000 * 60 * 60 * 24))),数据库只存原始时间字段 - 实在要在 SQL 层统一,用条件表达式模拟:MySQL 用
TIMESTAMPDIFF,SQL Server 用DATEDIFF,PostgreSQL 用减法 +EXTRACT,通过 ORM 或查询构建器动态切换 - 最容易被忽略的一点:所有数据库对
NULL输入都返回NULL,但没人提醒你检查——一个NULL时间戳会让整条WHERE条件静默失效










