datediff(now(), created_at) 返回整数天数差,仅比较日期部分、忽略时分秒,导致时间精度丢失,无法准确判断是否满7×24小时,边界数据(如当天23:59:59)可能被错误归入“0天”而漏判。

DATEDIFF 在 MySQL 中确实能算日期差,但直接用它过滤“最近七天”容易出错——因为它的结果是整数天数,且 DATEDIFF(NOW(), date_col) 返回的是“从 date_col 到今天过了多少整天”,不包含时间部分,会导致边界数据丢失(比如今天 15:00 查询,date_col = '2024-04-10 23:59:59' 会被算作 0 天,但严格来说已超 7×24 小时)。
为什么 DATEDIFF(NOW(), created_at)
MySQL 的 DATEDIFF 只比较日期部分(年月日),自动截断时间。这意味着:
-
DATEDIFF('2024-04-10 00:00:00', '2024-04-04 23:59:59')返回6,看似在 7 天内,但实际相差仅 5 天 0.0001 秒 - 反过来,
'2024-04-04 00:00:00'和'2024-04-10 23:59:59'也返回6,但已接近 7 整天边界 - 真实业务中,“最近七天”通常指
NOW() - INTERVAL 7 DAY之后的所有时间点,必须保留时分秒精度
更可靠的做法:用 DATE_SUB + 比较运算符
直接构造时间下界,让 MySQL 做原生时间戳比较,既准确又走索引(如果 created_at 有索引):
SELECT * FROM orders WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY);
等价写法(语义更直白):
SELECT * FROM orders WHERE created_at >= NOW() - INTERVAL 7 DAY;
注意点:
- 确保
created_at是DATETIME或TIMESTAMP类型;若为DATE,则本身无时分秒,DATEDIFF反而够用,但场景少见 - 避免写成
DATE(created_at) >= DATE_SUB(CURDATE(), INTERVAL 6 DAY)——这会强制对每行计算DATE(),无法使用索引 -
NOW()和CURDATE()在同一条语句中结果一致,但前者含时间,后者只有日期,别混用
如果非要用 DATEDIFF,怎么补救?
仅当字段类型确实是 DATE(如日志汇总表按天分区),且你明确接受“按日历日”而非“精确 168 小时”时才考虑。此时应写成:
SELECT * FROM daily_summary WHERE DATEDIFF(CURDATE(), stat_date) <p>关键细节:</p>
- 必须用
CURDATE()而非NOW(),否则DATEDIFF内部仍会转成日期,但语义混乱 表示包含今天、往前推 6 天,共 7 个自然日(今天 + 昨天 + … + 6 天前)- 若写成
,就变成 8 天了
真正要注意的不是函数名,而是你定义的“最近七天”到底指“7×24 小时窗口”还是“7 个日历日”。前者必须用 DATE_SUB(NOW(), INTERVAL 7 DAY),后者才可能用 DATEDIFF——但即便如此,也要确认字段类型和业务容忍度。











