79

I want to get all the rows from a table through an expression:

table.date <= 2014-07-10

But if the column contains a datetime let's say:

2014-07-10 12:00:00

But if I do:

where('date', '<=', $date)

it won't get the row.

I guess this is because $date = 2014-07-10 which makes MySQL assume that it is 2014-07-10 00:00:00.

In regular MySQL I would just do

where DATE(date) <= $date

What would be the equivalent using Laravel's Eloquent?

8 Answers 8

145

Laravel 4+ offers you these methods: whereDay(), whereMonth(), whereYear() (#3946) and whereDate() (#6879).

They do the SQL DATE() work for you, and manage the differences of SQLite.

Your result can be achieved as so:

->whereDate('date', '<=', '2014-07-10')

For more examples, see first message of #3946 and this Laravel Daily article.


Update: Though the above method is convenient, as noted by Arth it is inefficient on large datasets, because the DATE() SQL function has to be applied on each record, thus discarding the possible index.

Here are some ways to make the comparison (but please read notes below):

->where('date', '<=', '2014-07-10 23:59:59')

->where('date', '<', '2014-07-11')

// '2014-07-11'
$dayAfter = (new DateTime('2014-07-10'))->modify('+1 day')->format('Y-m-d');

->where('date', '<', $dayAfter)

Notes:

  • 23:59:59 is okay (for now) because of the 1-second precision, but have a look at this article: 23:59:59 is not the end of the day. No, really!
  • Keep in mind the "zero date" case ("0000-00-00 00:00:00"). Though, these "zero dates" should be avoided, they are source of so many problems. Better make the field nullable if needed.
Sign up to request clarification or add additional context in comments.

5 Comments

Again, I would advise against this method, it wraps the column in the DATE() function and the engine cannot use an index on the column.
No problem! I was wrong about dates being compared like strings, they just get converted and then compared. 2014-07-11 will be implicitly converted to 2014-07-11 00:00:00 before comparison, which fortunately holds up well with your other explanations.
Also note that instead of mucking around with the date in PHP, you can happily use WHERE date < :date + INTERVAL 1 DAY
Indeed about the MySQL INTERVAL. Though, when possible, I prefer doing processings the PHP side rather than MySQL or even Apache. I got tired of all their subtleties to manage.
THAX ALOT : where works for me i am using laravel 7+
10

Have you considered using:

where('date', '<', '2014-08-11')

You should avoid using the DATE() function on indexed columns in MySQL, as this prevents the engine from using the index.

UPDATE

As there seems to be some disagreement about the importance of DATE() and indexes, I have created a fiddle that demonstrates the difference, see POSSIBLE KEYS.

9 Comments

Why he should avoid using DATE() on indexed colums?
This could be a solution but seems more like a hack than best practice. What if a filed realy contains 00:00:00 as time.
@almo, Once you get used to how MySQL compares dates it isn't too bad. It is like string comparison; '2014-08-10 00:00:00' is greater than '2014-08-10'.
@Almo You should avoid using DATE() on a indexed column because it prevents MySQL to use this index. If possible use expressions on the right side of a comparison operator. And no, this is best practice not a hack!
::whereRaw("DATE(date) <= '2014-08-10'"). @Arth He didn't mentioned indexes, so I don't know what's the fuzz about it. @almo 2014-07-10 will be casted to DATETIME (2014-07-10 00:00:00) like you said. However, you're comparing a DATE against a DATETIME, you either cast the DATETIME to DATE or add 23:59:59 to $date.
|
8

You can get the all record of the date '2016-07-14' or before '2016-07-14' by choosing one syntax from follows:

->whereDate('date','=','2014-07-10')

->whereDate('date', '<=', '2014-07-10')

Or use the another code for dynamic date

whereDate('date',$date)

2 Comments

This doesn't appear to answer the question at all.
@SteveFromAccounting In which case, the code is not working for Laravel ? Can you send the code snippets?
4

You can use this

whereDate('date', '=', $date)

If you give whereDate then compare only date from datetime field.

Comments

4
use Carbon\Carbon;

public function scopePublished($query)
{
  $now = Carbon::now();
  $date = Carbon::parse($now)->toDateString();
  $time = Carbon::parse($now)->toTimeString();
  return $query->whereDate('published_at', '<', $date)
  ->orWhere(function($query) use ($date, $time) {
    $query->whereDate('published_at', '=', $date)
    ->whereTime('published_at', '<=', $time);
  });
}

Comments

2

If you're still wondering how to solve it.

I use

protected $dates = ['created_at', 'updated_at', 'aired'];

In my model and in my where i do

where('aired', '>=', time());

So just use the unix to compare in where.

In views on the other hand you have to use the date object.

1 Comment

this is the only one worked for me, because I have defined in $dates :) thanks
1

Here is my logic: if you are comparing date then your method should be whereDate and if your comparing complete datetime then your method will be only where:

$calendar_alert = DB::table('calendar_alerts')->whereDate('when', '=', now()->format('Y-m-d'))->where('when', '>', now()->format('H:i:s'))->get();

Comments

0

Facing the same issue, I suggest to read this article : https://dev.to/nicolus/how-to-properly-retrieve-laravel-models-between-two-dates-1bek

Note that the statement :

The issue here is that our created_at column is usually a Datetime, so it's not a simple date but it also has a time. Which means that in practice any post created on the 30th won't be retrieved because their creation date will always be greater than 2021-06-30 (which SQL will assume means '2021-06-30 00:00:00').

... from the article isn't completly true because on my side I tested a direct comparison between a mysql "date" typed field and a string formatted like "2022-10-18", and the issue was the same, the "<=" didn't work right.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.