MySQL的DATEDIFF()必须用DATEDIFF(结束日期,开始日期),否则得负数;它截断时间只算日历日,NULL任一参数结果即NULL;PG用date减法更自然;SQL Server的DATEDIFF(day)按跨天边界计数,非日历差。

MySQL里用DATEDIFF()算两个日期差,但参数顺序很关键
MySQL的DATEDIFF()只接受两个DATE或DATETIME类型参数,且**必须是DATEDIFF(结束日期, 开始日期)**——反过来会得到负数,容易误判。它自动截断时间部分,只按日历日计算,不考虑时分秒。
常见错误现象:DATEDIFF('2024-01-01', '2024-01-10')返回-9,而不是预期的9;或者传入TIMESTAMP却没意识到结果被向下取整到日粒度。
- 确保两个字段都是
DATE或能隐式转为DATE(比如CAST(created_at AS DATE)) - 如果需要包含时间精度(比如精确到小时),别用
DATEDIFF(),改用TIMESTAMPDIFF(DAY, start_time, end_time) - 注意NULL值:任一参数为
NULL,结果就是NULL,建议提前用COALESCE()兜底
PostgreSQL没有DATEDIFF(),直接用减法更自然
PostgreSQL里两个DATE相减直接返回INTEGER类型的天数,比如end_date - start_date。这是原生支持,无需函数封装,也不存在参数顺序陷阱。
使用场景:迁移MySQL代码到PG时,别硬套DATEDIFF()写法,否则报错function datediff(unknown, unknown) does not exist。
-
DATE减DATE→ 天数(整数) -
TIMESTAMP减TIMESTAMP→INTERVAL,需用EXTRACT(DAY FROM ...)或AGE()进一步处理 - 若字段含时区(如
TIMESTAMPTZ),减法结果仍为天数,但已自动按UTC对齐,一般无需额外转换
SQL Server的DATEDIFF()单位灵活,但容易误解“跨天”逻辑
SQL Server的DATEDIFF(day, start, end)计算的是两个时间点之间**边界跨越的天数**,不是日历差。比如DATEDIFF(day, '2024-01-01 23:59:59', '2024-01-02 00:00:01')返回1——哪怕只差2秒,也算跨了一天。
这和MySQL/PG按日历日相减的行为不同,容易在统计“停留天数”“有效期”等业务场景中出偏差。
- 若要严格按日历日差(忽略时间),先用
CONVERT(DATE, ...)截断再算 - 单位不限于
day,还可写hour、minute、month等,但注意month只看年月部分,不计算具体天数 - 参数顺序是
DATEDIFF(unit, start, end),和MySQL一致,但单位必须显式指定
跨数据库兼容写法几乎不存在,优先明确目标平台
想写一条SQL在MySQL、PG、SQL Server上都跑通?基本不可行。DATEDIFF()在各库参数个数、顺序、单位支持、NULL处理上全都不一样。强行抽象成统一函数,反而增加维护成本和隐性bug。
真正该做的,是在应用层或视图层隔离差异:比如在ORM里为不同方言注册各自的日期差计算方法,或在数据仓库建模时统一用DATE类型字段并约定只走日历日逻辑。
最容易被忽略的一点:很多业务系统把“创建时间”和“更新时间”存为TIMESTAMP,但报表需求只要“间隔几天”,这时候硬用DATEDIFF()可能引入毫秒级误差导致边界日多算/少算一天——不如一开始就CAST成DATE再减。

















