如何使用Laravel和Eloquent在两个日期之间查询?

245

我正在尝试创建一个报告页面,该页面显示从特定日期到特定日期的报告。 这是我的当前代码:

$now = date('Y-m-d');
$reservations = Reservation::where('reservation_from', $now)->get();

这段纯SQL的代码会执行以下操作:select * from table where reservation_from = $now

我有这个查询语句,但我不知道如何将它转换为Eloquent查询。

SELECT * FROM table WHERE reservation_from BETWEEN '$from' AND '$to

我该如何将上述代码转换为Eloquent查询?


reservation_from 中的日期格式是什么?您可以根据此使用 Carbon 值。 - Athi Krishnan
日期格式为TIMESTAMP @AthiKrishnan - wobsoriano
4
这段代码的意思是:查询时间从1975年5月21日至2015年5月21日之间的预订信息,并返回结果。 - Athi Krishnan
15个回答

463

whereBetween方法用于验证一列的值是否介于两个值之间。

$from = date('2018-01-01');
$to = date('2018-05-02');

Reservation::whereBetween('reservation_from', [$from, $to])->get();

在某些情况下,您需要动态添加日期范围。根据@Anovative的评论,您可以这样做:

Reservation::all()->filter(function($item) {
  if (Carbon::now()->between($item->from, $item->to)) {
    return $item;
  }
});

如果您想要添加更多的条件,那么您可以使用 orWhereBetween。如果您想要排除一个日期区间,那么您可以使用 whereNotBetween

Reservation::whereBetween('reservation_from', [$from1, $to1])
  ->orWhereBetween('reservation_to', [$from2, $to2])
  ->whereNotBetween('reservation_to', [$from3, $to3])
  ->get();

其他有用的where子句: whereIn, whereNotIn, whereNull, whereNotNull, whereDate, whereMonth, whereDay, whereYear, whereTime, whereColumn , whereExists, whereRaw.

Laravel关于Where子句的文档。


如果$from$to是属于模型的动态日期,该如何处理呢?比如说有一个effective_atexpires_at字段,我想查询当前项目是否在这个范围内。我尝试使用each()和一个if语句,其中使用了Carbon::now()->between( ... ),但它仍然返回所有结果。 - Rockin4Life33
5
忽略了filter()方法,这就解决了问题。MyModel::all()->where('column', 'value')->filter(function ($item) { if (Carbon::now->between($item->effective_at, $item->expires_at)) { return $item; } })->first(); - Rockin4Life33
1
@Anovative 感谢您的有用评论。我会根据您的评论更新我的答案。 - Peter Kota
3
第二种方法存在问题。它会将所有记录从数据库加载到内存中,然后才进行筛选过滤。 - Jino Antony
1
非常感谢你,你帮我省了很多时间! - sohaieb azaiez
显示剩余4条评论

28

我已经创建了模型范围

要了解更多关于作用域的内容,请查看下面的链接:

代码:

   /**
     * Scope a query to only include the last n days records
     *
     * @param  \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeWhereDateBetween($query,$fieldName,$fromDate,$todate)
    {
        return $query->whereDate($fieldName,'>=',$fromDate)->whereDate($fieldName,'<=',$todate);
    }

在控制器中,将Carbon库添加到顶部

use Carbon\Carbon;

获取从现在开始过去10天的记录

 $lastTenDaysRecord = ModelName::whereDateBetween('created_at',(new Carbon)->subDays(10)->startOfDay()->toDateString(),(new Carbon)->now()->endOfDay()->toDateString() )->get();

获取从现在开始最近30天的记录

 $lastThirtyDaysRecord = ModelName::whereDateBetween('created_at',(new Carbon)->subDays(30)->startOfDay()->toDateString(),(new Carbon)->now()->endOfDay()->toDateString() )->get();

1
WhereDateBetween 的第二个参数需要是一个数组。 - Dr. House
这只是模型的作用域,不是构建器方法。 - ManojKiran A
哦,是的,不知怎么错过了。我的错 :) - Dr. House

26

如果您的字段类型是 datetime 而不是 date虽然它适用于两种情况),另一个选项是:


$fromDate = "2016-10-01";
$toDate = "2016-10-31";

$reservations = Reservation::whereRaw(
  "(reservation_from >= ? AND reservation_from <= ?)", 
  [
     $fromDate ." 00:00:00", 
     $toDate ." 23:59:59"
  ]
)->get();

1
从技术上讲,它不需要是 $toDate . " 23:59.59.999" 吗? - stevepowell2000
@stevepowell2000 这取决于你的数据库,对于我来说,我们在datetime mysql字段中以'YYYY-MM-DD HH:MM:SS'格式存储日期,没有微秒精度。相关信息:https://dev.mysql.com/doc/refman/8.0/en/datetime.html - tomloprod
很好的观点。因此,如果它是一个日期时间或时间戳字段,我们可能需要一直到23:59:59.999999。“DATETIME或TIMESTAMP值可以包括高达微秒(6位数字)精度的尾随小数秒部分。” - stevepowell2000
1
谢谢你之前帮我完成任务!喜欢这个答案,兄弟! :) - habie - Habie Smart

23

如果您想检查当前日期是否在数据库中的两个日期之间: =>此查询将获取应用程序列表,如果员工的申请从和到的日期存在于今天的日期中。

$list=  (new LeaveApplication())
            ->whereDate('from','<=', $today)
            ->whereDate('to','>=', $today)
            ->get();

18
以下代码应该能够正常工作:
$now = date('Y-m-d');
$reservations = Reservation::where('reservation_from', '>=', $now)
                           ->where('reservation_from', '<=', $to)
                           ->get();

13

如果您需要在日期时间字段中包含"IN",则应该像这样:

return $this->getModel()->whereBetween('created_at', [$dateStart." 00:00:00",$dateEnd." 23:59:59"])->get();

2
你好,欢迎来到Stack Overflow。在回答已有多个答案的问题时,请确保添加一些额外的见解,说明你提供的响应是实质性的,而不仅仅是重复原始发布者已经审核过的内容。这在“仅代码”的答案中特别重要,例如你提供的答案。 - chb

12

尝试这样做:

由于您是基于单个列值获取数据,因此也可以简化查询:

$reservations = Reservation::whereBetween('reservation_from', array($from, $to))->get();

按条件检索:Laravel 文档

希望这可以帮到你。


2
如果您想要从2021年2月1日到5月31日的注册表,而该注册表是在2021年5月31日创建的,请注意它将无法正常工作。在这种情况下,您应该使用以下代码:whereDate('created_at', '>=', $this->start_date)->whereDate('created_at', '<=', $this->end_date)->get() - Freddy Daniel

6

我遵循其他贡献者提供的有价值的解决方案,但面临一个小问题没有得到解决。如果reservation_from是datetime列,则可能不会产生预期的结果,并且会错过日期相同但时间在00:00:00之后的所有记录。为了改进上述代码,需要进行一点微调,如下所示。

$from = Carbon::parse();
$to = Carbon::parse();
$from = Carbon::parse('2018-01-01')->toDateTimeString();
//Include all the results that fall in $to date as well
$to = Carbon::parse('2018-05-02')
    ->addHours(23)
    ->addMinutes(59)
    ->addSeconds(59)
    ->toDateTimeString();
//Or $to can also be like so
$to = Carbon::parse('2018-05-02')
    ->addHours(24)
    ->toDateTimeString();
Reservation::whereBetween('reservation_from', [$from, $to])->get();

4

我知道这可能是一个老问题,但我发现自己处于这样一种情况:我必须在Laravel 5.7应用程序中实现此功能。以下是对我有效的解决方案。

 $articles = Articles::where("created_at",">", Carbon::now()->subMonths(3))->get();

你还需要使用Carbon。
use Carbon\Carbon;

2

让我添加准确的时间戳并使用正确的语法。

之前:

$from = $request->from;
$to = $request->to;
Reservation::whereBetween('reservation_from', [$from, $to])->get();

之后

$from = date('Y-m-d', strtotime($request->from));
$to = date('Y-m-d', strtotime($request->to));
Reservation::whereBetween('reservation_from', [$from, $to])->get();

注意:如果您以字符串形式存储日期,请确保在from和to中传递精确的格式。这将与数据库匹配。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接