DATEDIFF()计算两日期天数差且只取日期部分,结果为整数;TIMESTAMPDIFF()支持小时等更小单位且参与完整时间计算;WHERE中避免函数包裹字段以防索引失效。

用 DATEDIFF() 计算两个日期字段之间的天数差
DATEDIFF() 是 MySQL 里最直接的天数差计算函数,它只关心日期部分(年月日),自动忽略时间。比如 DATEDIFF('2024-03-15 14:30:00', '2024-03-10 09:15:00') 返回 5,不是 5.22。
- 参数顺序很重要:第一个是结束日期,第二个是起始日期;结果为负说明起始晚于结束
- 如果字段类型是
DATETIME或TIMESTAMP,DATEDIFF()仍只取日期部分,不考虑时分秒 - 不能用于毫秒或分钟级精度需求——它天生就是“整日”单位
- 注意时区影响:若字段带时区(如
TIMESTAMP存储为 UTC),实际比较的是转换后的本地日期,可能和预期不符
用 TIMESTAMPDIFF() 算小时、分钟甚至更小单位
要精确到小时,必须用 TIMESTAMPDIFF(),它支持指定单位,且完整参与时间计算。例如:TIMESTAMPDIFF(HOUR, '2024-03-10 10:00:00', '2024-03-11 15:30:00') 返回 29。
- 单位参数必须大写:可用
SECOND、MINUTE、HOUR、DAY、WEEK、MONTH、YEAR - 参数顺序同
DATEDIFF():结束时间在前,开始时间在后 - 对
NULL值敏感:任一参数为NULL,结果直接是NULL,建议提前用IFNULL()或COALESCE()处理 - 性能略低于
DATEDIFF():因为要解析完整时间戳,大数据量时差异可测,但通常不明显
WHERE 条件中用日期差筛选数据时的常见陷阱
写 WHERE DATEDIFF(NOW(), created_at) > 7 看似合理,但容易出错——如果 created_at 是 TIMESTAMP 类型且服务器时区设置不一致,可能漏掉边界记录。
- 避免在函数中包裹字段:如
WHERE DATEDIFF(NOW(), created_at) > 7会导致created_at索引失效;应改写为WHERE created_at - 用
INTERVAL构造边界时间更安全,也支持索引,且语义清晰 - 如果字段是
DATE类型(无时间),NOW()会带上当前时间,导致当天数据被错误排除;此时应统一用CURDATE() - 跨日夏令时切换可能导致
HOUR差异常:比如某地凌晨2点跳到3点,两时间点间物理小时数少1,但TIMESTAMPDIFF(HOUR, ...)仍按标准小时算,需人工校验业务逻辑是否接受
处理时区不一致导致的计算偏差
当数据库服务器、客户端连接、字段类型三者时区配置不统一时,TIMESTAMPDIFF() 的结果可能和肉眼观察不符。例如,服务器设为 +08:00,但应用传入的字符串是 UTC 时间,MySQL 会先按连接时区转换再计算。
- 查当前会话时区:
SELECT @@session.time_zone;全局时区:SELECT @@global.time_zone - 临时切换会话时区:
SET time_zone = '+00:00',再执行计算,确保输入时间被当作 UTC 解析 - 推荐做法:存储统一用
TIMESTAMP+ UTC,读取时由应用层转本地时间;计算一律在 UTC 下进行,避免歧义 -
CONVERT_TZ()可以显式转换,但开销较大,仅在必要时用于调试或少量数据修正
DATEDIFF(),但只要涉及小时、分钟或需要严格对齐时间点,就必须切到 TIMESTAMPDIFF() 并确认时区上下文——这点容易被跳过,直到线上出现“差1小时”的诡异问题才回头排查。


















