whereDate()仅匹配日期部分(年月日),忽略时分秒,底层调用数据库DATE()函数,MySQL/MariaDB原生支持,PostgreSQL/SQLite需适配;不走索引,时区不一致易导致查询失败。

Where Date在Eloquent里到底匹配哪部分
whereDate() 只比较年月日,忽略时分秒。它底层会把字段转成 DATE() 类型再比对,所以哪怕数据库存的是 2024-05-20 14:30:45,whereDate('created_at', '2024-05-20') 也能命中。
但注意:这个函数依赖 MySQL 的 DATE() 函数行为,PostgreSQL 或 SQLite 需要额外处理(见下一条)。
- 只适用于 MySQL / MariaDB 默认行为;PostgreSQL 用
whereRaw("DATE(created_at) = ?", ['2024-05-20']) - 字段必须是
DATETIME或TIMESTAMP类型,DATE类型字段直接用where()更高效 - 如果字段有索引,
whereDate()通常无法走索引(MySQL 8.0+ 对函数索引支持有限,别指望它快)
想查“今天”或“本周”,别硬写字符串
用 Carbon 生成动态日期比手拼 '2024-05-20' 更可靠,也避免时区错乱。
例如查今天的数据:
立即学习“PHP免费学习笔记(深入)”;
$today = Carbon::today(); // 自动取当前时区的 00:00:00
$posts = Post::whereDate('published_at', $today)->get();
查本周一到周日(按 locale):
$start = Carbon::now()->startOfWeek();
$end = Carbon::now()->endOfWeek();
$posts = Post::whereBetween('published_at', [$start, $end])->get();
-
whereDate()不能传 Carbon 实例数组,只能单值;范围查询必须用whereBetween()或whereRaw() - 如果应用部署在 UTC,但业务按东八区算“今天”,得先调
Carbon::setTestNow()或显式用Carbon::today('Asia/Shanghai') -
startOfWeek()默认是周一,Laravel config 中'app.locale'不影响它,要改得传参数:startOfWeek(Carbon::SUNDAY)
whereYear/month/day 这些函数容易被忽略的细节
whereYear('created_at', 2024) 看似简单,但它在 MySQL 里实际执行的是 YEAR(created_at) = 2024 —— 同样不走索引,且对 NULL 值返回 false(哪怕字段允许 NULL)。
-
whereMonth('created_at', 5)会匹配所有 5 月的记录,不管年份;常被误用在“今年 5 月”场景,这时应组合whereYear()+whereMonth() - 这些函数在 SQLite 中表现一致,但 PostgreSQL 需要
EXTRACT(YEAR FROM created_at),Laravel 底层已适配,不用手动写whereRaw - 如果字段是
DATE类型(无时间),whereYear()效率仍低于whereBetween(),因为后者能利用范围索引
时区错乱导致查不到数据的典型场景
最常见的情况:数据库存的是 UTC 时间(Laravel 默认),但 Carbon::today() 拿的是应用时区(比如 Asia/Shanghai),两者差 8 小时,whereDate() 就会跨天。
比如数据库里存 2024-05-20 16:00:00 UTC,对应北京时间是 2024-05-21 00:00:00。你用 Carbon::today() 得到 2024-05-21,但 whereDate() 在数据库里查的是 UTC 的日期部分,即 2024-05-20,结果为空。
- 解决方法一:统一用 UTC 处理,
Carbon::today('UTC')再传给whereDate() - 解决方法二:用
whereBetween()显式转换时区:whereBetween('created_at', [now()->startOfDay()->tz('UTC'), now()->endOfDay()->tz('UTC')]) - 别依赖
date_default_timezone_set(),Eloquent 和 Carbon 的时区逻辑是独立控制的
日期部分匹配看着简单,真正上线后出问题,八成卡在时区和索引这两块。动手前先确认存储时区、应用时区、查询构造方式三者是否对齐。



















