Laravel按认证用户时区处理whereDate日期筛选的实现问题
最优解决方案:应用层转换用户输入时区
核心思路是不对数据库存储的created_at字段做时区转换(避免无法使用索引导致性能下降),而是将用户传入的日期先转换为数据库默认时区的完整时间范围,再进行查询。
具体实现代码如下:
// 1. 将用户传入的起始日期转换为「用户时区当天0点」,再转成数据库默认时区 $start = \Carbon\Carbon::createFromFormat('Y-m-d', $request->start_date, $user->timezone) ->startOfDay() ->setTimezone(config('app.timezone')); // 2. 将用户传入的结束日期转换为「用户时区当天23:59:59」,再转成数据库默认时区 $end = \Carbon\Carbon::createFromFormat('Y-m-d', $request->end_date, $user->timezone) ->endOfDay() ->setTimezone(config('app.timezone')); // 3. 直接用时间范围查询,不要用whereDate $trips->where('created_at', '>=', $start) ->where('created_at', '<=', $end);
该方案完全兼容你的现有业务逻辑,数据库字段可以正常走索引,大表场景下性能优势非常明显。以你举的示例验证:用户选2020-06-12(EST时区)作为起始日期,转换后得到PST时区的2020-06-11 21:00:00,数据库存储的2020-06-11 23:00:00会被命中,符合预期。
可选方案:数据库层面转换时区(不推荐)
如果特殊场景需要直接在查询时转换时区,可以使用数据库自带的时区转换函数,缺点是无法用到created_at的索引,大表查询性能差,同时需要保证数据库时区名称和PHP使用的时区名称一致。MySQL环境下实现代码如下:
use Illuminate\Support\Facades\DB; $trips->whereDate( DB::raw("CONVERT_TZ(created_at, '".config('app.timezone')."', '".$user->timezone."')"), '>=', $request->start_date );
内容的提问来源于stack exchange,提问作者Kunal Rajput
相关产品推荐
相关产品推荐

