游乐游手机版
首页/数据库/文章详情

如何在MySQL中计算两个日期相差天数的详细方法

时间:2026-07-17 21:13
MySQL中计算日期差常用DATEDIFF(),返回忽略时间的整数天数差,参数顺序决定正负。需时间精度时改用TIMESTAMPDIFF(),支持指定单位。WHERE条件中函数套列名会导致索引失效,应将函数移至等号右侧,保持左侧为裸列名。

在 MySQL 中计算日期差是开发中的常见操作,但也是容易踩坑的高频场景。这里总结了几处关键注意事项:DATEDIFF() 返回的是忽略时间的整数天数差,参数顺序直接决定结果的正负;如果需要考虑时间精度,必须改用 TIMESTAMPDIFF();另外,在 WHERE 条件中直接对列名套用函数,会导致索引失效——这一点最容易被忽视,也最容易引发性能问题。

如何在MySQL中计算两个日期相差的天数?

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

DATEDIFF() 是 MySQL 中最直观的日期差计算函数,没有之一。它返回两个日期之间相差的完整天数,仅识别日期部分,时间部分直接被忽略。结果是一个整数,正负取决于你参数的摆放顺序:DATEDIFF(end_date, start_date)——end 在后,start 在前,如果 end 晚于 start,则返回正数。

举例说明:DATEDIFF('2024-01-05', '2024-01-01') 返回的是 4,不是 5。传入参数时,MySQL 会自动识别 '2024-01-01 14:30:00' 这样的格式,但只取日期部分,时间直接被丢弃。所以,想连同时间一起计算?别指望它。

有几个坑需要提前注意:

  • 不能传入 NULL,否则整个结果直接变为 NULL。建议在排序前先用 IFNULL()COALESCE() 做兜底处理。
  • 不支持毫秒级精度,时区也不纳入考虑。哪怕字段是 TIMESTAMP 类型,它也只关注日期那几位数字。

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

场景变了:想计算“从 2024-01-01 10:00:00 到 2024-01-02 15:30:00 差了多少小时”,DATEDIFF() 就完全无能为力了。这时候必须请出 TIMESTAMPDIFF()——它支持按指定单位进行精确计算,单位可以是 DAYHOURMINUTE,甚至 MONTHYEAR

语法是 TIMESTAMPDIFF(unit, datetime_expr1, datetime_expr2),注意顺序:第二个参数作为起点,第三个参数作为终点,与 DATEDIFF() 保持一致。例如 TIMESTAMPDIFF(HOUR, '2024-01-01 10:00:00', '2024-01-02 15:30:00') 返回 27,非常精确。

单位必须大写,支持的枚举值有:SECONDMINUTEHOURDAYWEEKMONTHQUARTERYEAR
有一个隐蔽的坑:如果两个 datetime 值类型不一致——比如一个是 DATE,一个是 DATETIME——MySQL 会进行隐式转换,DATE 被当作当天零点,这样容易莫名其妙地多算或少算一整天。

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

很多新手喜欢在查询中写 WHERE DATEDIFF(NOW(), created_at) > 30,看起来挺直观。但这样写,created_at 字段上的索引就直接失效了——函数套在列上,优化器无法进行范围扫描。

正确的做法是把函数移到等号右边:WHERE created_at < DATE_SUB(NOW(), INTERVAL 30 DAY)。如果想更简洁,可以写成 WHERE created_at < NOW() - INTERVAL 30 DAY。核心原则就一条:表达式左边必须是裸列名,不带任何函数或运算。
同理,TIMESTAMPDIFF(DAY, created_at, NOW()) > 30 也会导致索引失效,必须改写成 created_at < NOW() - INTERVAL 30 DAY

跨月/跨年时 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() 写法,可能让原本毫秒级的查询直接飙到数秒,教训确实不少。

来源:https://www.php.cn/faq/2820214.html
上一篇MySQL执行环境中SQL_MODE参数设置对SQL解析流程的详细影响 下一篇Oracle 12c存储过程ORA-01555错误原因分析
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
MySQL千万级大表如何平滑DDL变更避免长时间锁表
数据库 · 2026-07-17

MySQL千万级大表如何平滑DDL变更避免长时间锁表

MySQL8 0 12+对末尾添加允许NULL且无默认值的字段支持INSTANT算法秒级完成,避免锁表与主从延迟。否则需用pt-osc或gh-ost,并注意触发器延迟、binlog格式需设置为行模式、主从延迟及连接池及时进行刷新,防止业务抖动与中断,确保稳定。

MySQL外键约束大批量导入数据性能影响原因
数据库 · 2026-07-17

MySQL外键约束大批量导入数据性能影响原因

MySQL中外键校验逐行进行,无法批量合并,每行插入均触发独立存在性检查、加锁与释放,高并发下IO和锁竞争指数级放大。需为外键字段创建高效索引,慎用ONDELETECASCADE,必要时将校验移至应用层。

SQL窗口函数统计连续登录天数的方法
数据库 · 2026-07-17

SQL窗口函数统计连续登录天数的方法

连续登录天数统计通过登录日期减去窗口函数ROW_NUMBER()行号构造恒定分组标识实现,需用DATEDIFF等适配数据库差异,筛选至少连续3天用户应在外层按user_id聚合取最大值判断,并注意联合索引避免全表排序。

Redis集群状态fail时用redis-cli修复槽位方法
数据库 · 2026-07-17

Redis集群状态fail时用redis-cli修复槽位方法

Redis集群状态cluster_state:fail的根源包括主节点宕机、网络故障或槽位未分配等。redis-cli--clusterfix仅适用于节点在线且通信正常时的槽位空缺场景,无法处理进程挂掉或网络问题。使用前需验证节点连接、数量及槽位分配状态,否则可能掩盖问题或导致数据永久丢失。fix无效时应检查日志、手动补节点或重建集群。

Oracle安装报错INS-13001环境不支持?命令行加参数忽略
数据库 · 2026-07-17

Oracle安装报错INS-13001环境不支持?命令行加参数忽略

在Windows高版本操作系统安装Oracle时,若遇INS-13001不支持环境报错,可通过命令行添加`-ignorePrereq`跳过所有系统检查,或以`-J "-Doracle install db validate supportedOSCheck=false "`禁用特定系统校验。需以管理员身份运行CMD,切勿双击setup exe,并确保主机名和IP