怎样在MySQL中计算两个日期相差的天数?

作者:袖梨 2026-07-16
DATEDIFF() 返回两日期间整数天数差,忽略时间部分;参数顺序决定正负,不支持NULL、毫秒和时区;需高精度用TIMESTAMPDIFF();WHERE中函数作用于列会导致索引失效。

用 DATEDIFF() 函数直接获取整数天数差

DATEDIFF() 是 MySQL 里最常用也最直观的日期差计算函数,它返回两个日期之间相差的完整天数(只算日期部分,忽略时间)。结果是整数,正负取决于参数顺序:DATEDIFF(end_date, start_date) 返回正数表示 end 在 start 之后。

  • 如果 start_date'2024-01-01'end_date'2024-01-05'DATEDIFF('2024-01-05', '2024-01-01') 返回 4
  • 参数必须是合法日期或能自动转换的字符串(如 '2024-01-01 14:30:00' 会被截断为 '2024-01-01'
  • 不能传入 NULL,否则整个结果为 NULL,建议提前用 IFNULL()COALESCE() 处理
  • 不支持毫秒级精度,也不考虑时区——哪怕字段是 TIMESTAMP 类型,DATEDIFF() 也只比对日期部分

需要包含时间精度时改用 TIMESTAMPDIFF()

当你要算“从 2024-01-01 10:00:00 到 2024-01-02 15:30:00 相差多少小时”,DATEDIFF() 就不够用了。这时候得用 TIMESTAMPDIFF(),它支持按指定单位(DAYHOURMINUTE 等)计算两个 datetime 的精确差值。

  • 语法是 TIMESTAMPDIFF(unit, datetime_expr1, datetime_expr2),注意:第二个参数是起点,第三个是终点,和 DATEDIFF() 顺序一致
  • 想算小时差就写 TIMESTAMPDIFF(HOUR, '2024-01-01 10:00:00', '2024-01-02 15:30:00'),结果是 27
  • 单位必须大写,且只能是 MySQL 支持的枚举值(SECONDMINUTEHOURDAYWEEKMONTHQUARTERYEAR
  • 如果两个 datetime 值类型不一致(比如一个是 DATE,一个是 DATETIME),MySQL 会隐式转换,但可能出人意料——DATE 被转成当天零点,容易导致多算或少算一整天

WHERE 条件里计算日期差要小心索引失效

在查询中写 WHERE DATEDIFF(NOW(), created_at) > 30 看似合理,但会让 created_at 字段上的索引完全失效,因为函数作用于列上,优化器无法使用 B+ 树索引做范围扫描。

  • 正确写法是把函数移到右边:WHERE created_at
  • 等价但更清晰的写法:WHERE created_at
  • 只要表达式左边是纯列名(不包裹函数或运算),MySQL 才可能走索引
  • 同理,TIMESTAMPDIFF(DAY, created_at, NOW()) > 30 也会使索引失效,必须改写为 created_at

跨月/跨年时 DATEDIFF() 和 TIMESTAMPDIFF(MONTH) 行为不同

DATEDIFF() 只认日历天数,而 TIMESTAMPDIFF(MONTH, ...) 计算的是“月份差”,不是简单除以 30。比如从 1 月 31 日到 2 月 28 日(非闰年),DATEDIFF() 返回 28,但 TIMESTAMPDIFF(MONTH, '2024-01-31', '2024-02-28') 返回 0,因为还没满一个月。

  • TIMESTAMPDIFF(MONTH, d1, d2) 的逻辑是:先比较年份差 ×12,再加月份差,最后看日部分是否“够格”——只有当 d2 的日 ≥ d1 的日时,才计入这个月
  • 所以 TIMESTAMPDIFF(MONTH, '2024-01-15', '2024-02-14')0,而 '2024-01-15''2024-02-15' 才是 1
  • 别指望用 DATEDIFF() 除以 30 来模拟月差,误差会很大;也别用 TIMESTAMPDIFF(MONTH, ...) 去反推具体天数——它不保证可逆

实际业务里最容易被忽略的是时间类型隐式转换和索引失效这两点。尤其当表数据量上去之后,一个没注意的 DATEDIFF() 写法可能让查询从毫秒变几秒。

相关文章

精彩推荐