DATEDIFF在SQL Server中按DATEDIFF(datepart, startdate, enddate)计算跨边界次数,非简单相减;必须显式指定单位(如day/dd),参数顺序错误会导致负值,且不支持变量传入datepart。

DATEDIFF 函数的基本用法和参数顺序
DATEDIFF 在 SQL Server 中不是“两个日期相减”,而是按指定单位计算「从第一个日期到第二个日期」的边界跨越次数。关键点在于:参数顺序是 DATEDIFF(datepart, startdate, enddate),不是 DATEDIFF(startdate, enddate)。写反会导致结果为负数,但很多人误以为负号是 bug,其实只是方向反了。
计算天数必须显式指定 day(或简写 dd),不能省略。SQL Server 不支持类似 PostgreSQL 的 end - start 直接减法语法。
-
DATEDIFF(day, '2024-01-01', '2024-01-05')→ 返回4(不是 5) -
DATEDIFF(day, '2024-01-05', '2024-01-01')→ 返回-4 - 错误写法:
DATEDIFF('2024-01-01', '2024-01-05')→ 报错:“参数个数不正确”
为什么 DATEDIFF(day, ...) 有时返回意外值?
因为 DATEDIFF 计算的是「日历日边界」跨越数,**不看具体时间部分**。只要跨过午夜 00:00,就算 1 天。比如:
-
DATEDIFF(day, '2024-01-01 23:59:59', '2024-01-02 00:00:01')→ 返回1(只差 2 秒,但跨了日界) -
DATEDIFF(day, '2024-01-01 00:00:00', '2024-01-01 23:59:59')→ 返回0(同一天内,无论多晚)
如果你要算“精确到秒的小时差再转天数”,别用 DATEDIFF(day, ...),改用 DATEDIFF(second, ...)/86400.0 或先 CAST 到 date 类型再减(仅适用于 SQL Server 2008+)。
和直接用 date 类型相减的区别
SQL Server 支持 date 类型直接相减(如 '2024-01-05' - '2024-01-01'),结果是整数天数,且**自动截断时间部分**。但它不适用于 datetime 或 datetime2 —— 这些类型直接减会报错。
- 安全写法(兼容所有日期类型):
DATEDIFF(day, @start, @end) - 简洁写法(仅限两个
date值):CONVERT(int, @end - @start) - 危险写法:
@dt1 - @dt2(datetime类型会触发隐式转换,可能出错或精度丢失)
注意:DATEDIFF 对 datetime2 精度无影响,它只关心日历日,不解析纳秒级差异。
常见错误:WHERE 条件里用 DATEDIFF 导致索引失效
在查询中写 WHERE DATEDIFF(day, OrderDate, GETDATE()) ,SQL Server 无法使用 <code>OrderDate 上的索引,因为函数作用于列上。等价且可走索引的写法是:
WHERE OrderDate >= DATEADD(day, -7, CAST(GETDATE() AS date))
这样把计算移到右边,左边保持裸列引用。如果 OrderDate 是 datetime 类型,还建议用 DATEADD(day, -7, DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0)) 来对齐到当天 00:00,避免时区或时间部分干扰。
实际业务中,最易被忽略的是:DATEDIFF 的 datepart 参数不支持变量,也不能拼字符串传入;必须是字面量,比如 dd、day、mm,不能写成 @unit。

















