【问题标题】:Laravel $q->where() between datesLaravel $q->where() 日期之间
【发布时间】:2014-09-09 13:39:50
【问题描述】:

我正在尝试让我的 cron 仅获得 Projects ,这些 Projects 将在接下来的 7 天内重复/续订以发送提醒电子邮件。我刚刚发现我的逻辑不太行。

我目前有查询:

$projects = Project::where(function($q){
    $q->where('recur_at', '>', date("Y-m-d H:i:s", time() - 604800));
    $q->where('status', '<', 5);
    $q->where('recur_cancelled', '=', 0);
});

但是,我意识到我需要做的是:

伪 SQL:

SELECT * FROM projects WHERE recur_at > recur_at - '7 days' AND /* Other status + recurr_cancelled stuff) */

我将如何在 Laravel 4 中执行此操作,并且使用 DATETIME 数据类型,我只使用时间戳完成了这种事情。

更新:

在使用以下代码后设法解决了这个问题,当您可以提取一些代码并脱离上下文查看它们时,Stackoverflow 也有帮助。

$projects = Project::where(function($q){
    $q->where(DB::raw('recur_at BETWEEN DATE_SUB(NOW(), INTERVAL 7 DAY) AND NOW()'));
    $q->where('status', '<', 5);
    $q->where('recur_cancelled', '=', 0);
});

更新问题:在 Laravel/Eloquent 中是否有更好的方法来做到这一点?

更新 2:

第一个解决方案在进一步测试后结果不正确,我现在解决并测试了以下解决方案:

$projects = Project::where(function($q){
    $q->where('recur_at', '<=', Carbon::now()->addWeek());
    $q->where('recur_at', '!=', "0000-00-00 00:00:00");
    $q->where('status', '<', 5);
    $q->where('recur_cancelled', '=', 0);
});

【问题讨论】:

  • 据我所知,您必须使用DB::raw,所以没有其他方法可以单独使用 Eloquent。另一方面,您为什么使用 DATETIME 而不是 TIMESTAMP 列?我要问的问题与原始问题无关,但与 DATETIME 相比,TIMESTAMP 更适合许多用例。
  • @N.B. DATETIME 似乎是 Laravel 使用的“标准”时间字段,所以我一直使用它。
  • 你可以使用 whereRaw(sql) 代替 where(DB::raw(sql))
  • @MrShibby 我想我有点喜欢where(DB::raw()) 格式,因为它看起来更清晰一些。 whereRaw() 更好有什么技术原因吗?
  • @Jono20201 - 不,这不是标准时间字段。标准时间字段是并且始终是TIMESTAMP。原因是 TIMESTAMP 始终采用 UTC,使用 DATETIME 您应该知道它来自哪个时区,以便您可以为其他时区的用户执行时间转换。甚至 Eloquent 也使用时间戳类型而不是日期时间。两种类型都向您显示完全相同的格式化日期,因此我强烈建议您使用时间戳而不是日期时间。

标签: php mysql laravel eloquent datetime-format


【解决方案1】:

您可以直接链接您的wheres,无需function(q)。 laravel 中还有一个不错的日期处理包,叫做Carbon。所以你可以这样做:

$projects = Project::where('recur_at', '>', Carbon::now())
    ->where('recur_at', '<', Carbon::now()->addWeek())
    ->where('status', '<', 5)
    ->where('recur_cancelled', '=', 0)
    ->get();

只需确保您在作曲家中需要 Carbon 并且您使用的是 Carbon 命名空间(使用 Carbon\Carbon;),它应该可以工作。

编辑: 作为Joel said,你可以这样做:

$projects = Project::whereBetween('recur_at', array(Carbon::now(), Carbon::now()->addWeek()))
    ->where('status', '<', 5)
    ->where('recur_cancelled', '=', 0)
    ->get();

【讨论】:

  • 看起来不错,但只是提醒您不需要双 where 子句,您可以改用 whereBetween。
  • @JoelHinz 不错!将来肯定会使用它。快速浏览 api 并感谢你我发现还有 orBetween 等等......
  • 我设法通过使用$q-&gt;where('recur_at', '&lt;=', Carbon::now()-&gt;addWeek()); 获得了预期的效果。我更喜欢使用function($q),因为我认为它使我更容易阅读代码。
  • 哦,现在我看到我给出了过去的日期,而你想要下一周,对不起,但你明白了 :) 我已经编辑了答案
  • @Tom Great,勾选了你的答案。我花了几分钟时间和我的商业伙伴一起计算数学,使用 Carbon 让它变得更简单。
【解决方案2】:

不想惹碳。所以这是我的解决方案

$start = new \DateTime('now');
$start->modify('first day of this month');
$end = new \DateTime('now');
$end->modify('last day of this month');

$new_releases = Game::whereBetween('release', array($start, $end))->get();

【讨论】:

  • 很好的解决方案。请注意,Carbon 是 DateTime 类的扩展。如果在解决方案中将DateTime 替换为Carbon,结果完全一样。
【解决方案3】:

@Tom : 如果我们提供以下格式的日期,而不是使用 'now' 或 'addWeek',它不会给出正确的记录

$projects = Project::whereBetween('recur_at', array(new DateTime('2015-10-16'), new DateTime('2015-10-23')))
->where('status', '<', 5)
->where('recur_cancelled', '=', 0)
->get();

它提供日期形式为 2015-10-16 到小于 2015-10-23 的记录。 如果 recur_at 的值为 2015-10-23 00:00:00 那么只有 它显示该记录 否则如果是 2015-10-23 12:00:45不显示

【讨论】:

    【解决方案4】:

    已编辑:请注意,
    whereBetween('date',$start_date,$end_date)
    包括第一次约会。

    【讨论】:

    • 不正确。您可能看到的是日期时间不准确。只需执行 $startDate-&gt;startOfDay();$endDate-&gt;endOfDay() 否则它默认为现在的任何时间。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-06
    • 1970-01-01
    • 2016-08-15
    • 2017-05-05
    • 1970-01-01
    相关资源
    最近更新 更多