CURDATE()返回当前日期(YYYY-MM-DD),用于匹配DATE字段;若字段为DATETIME/TIMESTAMP,应使用DATE(col)=CURDATE()(索引失效)或范围查询col>=CURDATE() AND col<DATE_ADD(CURDATE(), INTERVAL 1 DAY)(推荐,可走索引)。

用 CURDATE() 获取当天日期并匹配数据
直接用 CURDATE() 是最稳妥的方式,它返回的是当前日期(不带时间部分),适合和 DATE 类型字段或 DATE(时间字段) 对齐。如果业务表里存的是 DATETIME 或 TIMESTAMP,别直接拿 WHERE create_time = CURDATE() —— 这会漏掉所有带时间部分的记录,因为 CURDATE() 是 '2024-06-15',而 create_time 是 '2024-06-15 10:23:45',两者不等。
正确写法是把时间字段转成日期再比对:
SELECT * FROM orders WHERE DATE(create_time) = CURDATE();
-
DATE(create_time)会截掉时分秒,只保留日期部分,和CURDATE()类型一致 - 注意:这个写法在
create_time字段上有索引时,无法走索引,大数据量下可能变慢 - 如果查询频繁且数据量大,建议改用范围查询(见下一节)
用时间范围查询避免函数包裹字段
想让查询走索引,就得避免在索引字段上套函数。核心思路是算出当天的起始和结束时间点,用 BETWEEN 或两个 >=/< 条件。
推荐写法(兼容性好、可走索引):
SELECT * FROM orders WHERE create_time >= CURDATE() AND create_time < DATE_ADD(CURDATE(), INTERVAL 1 DAY);
-
CURDATE()返回当天 00:00:00,DATE_ADD(CURDATE(), INTERVAL 1 DAY)返回明天 00:00:00 - 用
<而不是<=,能精准覆盖到23:59:59.999999,不会跨天 - 只要
create_time有 B+Tree 索引,这条就能命中索引 - 别用
STR_TO_DATE(CONCAT(CURDATE(), ' 23:59:59'), '%Y-%m-%d %H:%i:%s')—— 多余且易出错
注意时区问题:服务器时间 vs 业务时间
MySQL 的 CURDATE() 和 NOW() 返回的是服务器所在时区的时间。如果你的业务用户分布在全国甚至全球,而数据库部署在 UTC 时区的云服务器上,那 CURDATE() 返回的就不是“中国用户当天”的日期。
- 查前先确认
SELECT NOW(), @@time_zone;,看当前会话时区是否符合业务预期 - 如果业务按东八区(
'+08:00')算当天,但服务器是 UTC,得显式转换:CONVERT_TZ(NOW(), '+00:00', '+08:00') - 更稳妥的做法是在应用层生成当天的起止时间戳,传参给 SQL,避免依赖数据库时区
-
TIMESTAMP类型字段会自动按会话时区转换,DATETIME则原样存储——选哪种类型会影响结果一致性
区分“当天”和“最近24小时”
业务常说的“当天”,是指自然日(00:00–23:59),不是从现在往前推24小时。这点容易混淆,尤其在凌晨时段查数据时。
- 错误写法:
WHERE create_time > DATE_SUB(NOW(), INTERVAL 24 HOUR)—— 这查的是过去24小时,比如今天早上6点查,会包含昨天早上6点之后的数据 - 正确做法始终以
CURDATE()或日期边界为准,而不是相对时间 - 如果真要查“最近24小时”,那是另一个需求,不能和“当天”混用
真正麻烦的不是写法,而是字段类型、索引设计和时区配置这三者没对齐——随便一个没配对,查出来的“当天数据”就可能是错的。


















