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?
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.
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.
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)
You can use this
whereDate('date', '=', $date)
If you give whereDate then compare only date from datetime field.
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);
});
}
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();
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.
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.
Related
I'm trying to query based on two databases and columns.
$model->where('response_time', '<=', Carbon::now()->subMinutes(\DB::raw('anotherTable.created_at'))->diffInMinutes(Carbon::now()))
response_time contains an integer of minutes, ie: 15
If the anotherTable.created_at - response_time (ie, sub 15 mins) is less than the current time, return the row.
I've tried the above but I'm having no luck and no idea how to debug my query. Any help appreciated.
Example query that should pass and return its row (1 minute over):
response_time 15
anotherTable.created_at 21-03-2022 13:40:00
Current time: 21-03-2022 13:56:00
Why Carbon is not working
Carbon is unable to retrieve the value from the database during query generation on the PHP side ($model->where()). Carbon will instead execute immediately on the string value of 'anotherTable.created_at' prior to issuing the query to the database. The equivalent of:
$offset = Carbon::now()
->subMinutes('anotherTable.created_at')
->diffInMinutes(Carbon::now()); // 0
$model->where('response_time', '<=', $offset); // WHERE responst_time <= 0
Carbon Process Breakdown
Carbon\Traits\Date::__call() is used to parse the action and units from the method name as sub and minutes.
The process conditionally calls Carbon\Traits\Units::subUnit('minute', 'anotherTable.created_at') [sic] which calls Carbon\Traits\Units::addUnit($unit, -$value, $overflow) [sic].
The -$value is ultimately processed by PHP as -'anotherTable.created_at' resulting in 0 as if you called Carbon::now()->subMinutes(0).
The issue would have been pointed out if Carbon would throw a TypeError exception when provided a string for the $value argument, as opposed to the expected int. However, the $value argument of Carbon\Traits\Units::subUnit($unit, $value) is not type-hinted.
MySQL Resolution
Instead of using Carbon, use the MySQL TIMESTAMPDIFF() function to produce the difference in minutes between anotherTable.created_at and NOW() in the query.
db<>fiddle Example
Provided anotherTable is being added with a JOIN in the query.
$model->where(
'response_time', '<=', DB::raw('TIMESTAMPDIFF(MINUTE, anotherTable.created_at, NOW())')
);
Give this a try :)
$model->where('response_time', '<=', Carbon::now()
->diffInMinutes(\DB::raw('anotherTable.created_at')));
You cannot rely on the table values being used in a carbon function.
Instead, you have to do your caulcations on the database.
The code below should work in theory, though I have not tested it out.
All culcations that require database data, are done on the database.
Carbon is only used to pass the condition value up to it.
$model->where(
DB::raw('DATE_SUB(anotherTable.created_at, INTERVAL response_time MINUTE)'), '<=', Carbon::now()
);
i hope this will help you
Carbon::parse('21-03-2022 13:40:00')->diffInMinutes(new DateTime)
Or
Carbon::parse('21-03-2022 13:40:00')->diffInMinutes(Carbon::now())
in your case use this:
Carbon::parse(DB::raw('anotherTable.created_at'))->diffInMinutes(Carbon::now())
I need to grab this month data for user in database so I write:
dd($user->products->where('paid',1)->where('created_at','>=', Carbon::now()->startOfMonth()->toDateString())->all());
and I got 0 results...
When I try Carbon::now()->subMonth() its works good but return me last 30 days ...
How I can solve this? How to get only this month data ?
->toDateString() is causing the query to look for a string value, and not a date. There's two ways to solve this:
(...)->where('created_at', '>=', Carbon::now()->startOfMonth())
// OR
(...)->whereDate('created_at', '>=', Carbon::now()->startOfMonth()->toDateString())
If you just use a Carbon variable, Laravel knows to check for date logic. Alternatively, if you're using a string, you can override the where logic to treat it as a date by using ->whereDate()
Now I send a message to my inbox app. You can see saved a message in image:
Message send in 16:55. But in my local site date of message incorrectly displayed:
Why is the date sent message not displayed correctly? Laravel app config timezone set "Asia/Tashkent"
Code:
$today = Inbox::where($message, $user_id)->whereDate('created_at', Carbon::today())->latest()->paginate($perPage);
$thisYear = Inbox::where($message, $user_id)->whereBetween('created_at', [now()->startOfYear(), Carbon::yesterday()->endOfDay()])->latest()->paginate($perPage);
$pastYear = Inbox::where($message, $user_id)->where('created_at', '<', now()->startOfYear())->latest()->paginate($perPage);
As said in the comments, you're formatting this date with created_at->format('H:m').
In PHP, m refers to the month, not the minute, which is i. It's printing 01 because that's the date's month.
Use this instead:
created_at->format('H:i')
Please try that way :
$today = Inbox::where($message, $user_id)->whereDate('created_at',DB::raw('CURDATE()'))->latest()->paginate($perPage);
Let’s say you want to filter out entries created today. You have a timestamp field created_at, right? How do you filter the DATE only from that timestamp? Apparently, Taylor thought about it.
I’ve seen people doing it with raw queries, like this:
$q->where(DB::raw("DATE(created_at) = '".date('Y-m-d')."'"));
Or without raw queries by datetime, like this:
$q->where('created_at', '>=', date('Y-m-d').' 00:00:00'));
Luckily, Laravel Query Builder offers a more Eloquent solution:
$q->whereDate('created_at', '=', date('Y-m-d'));
Or, of course, instead of PHP date() you can use Carbon:
$q->whereDate('created_at', '=', Carbon::today()->toDateString());
I'm trying to fetch relational data from a model where the date column is higher or equal to the current time.
The date column is formated as this: Y-m-d H:i:s
What I'm trying to do is to grab all rows where the Y-m-d H:i:s is in the future.
Example: lets assume the date is 2017-06-01 and the time is 09:00:00
Then i would like got all rows where the date is in the future, and the time is in the future.
Currently my code looks like this, and it's almost working but it doesn't grab the rows where the date is the current day.
public function customerCardFollowups() {
return $this -> hasMany('App\CustomerCardFollowup', 'user_id') -> whereDate('date', '>', Carbon::now('Europe/Stockholm')) -> orderBy('date', 'asc') -> take(20);
}
What am I doing wrong?
Sounds like you need to use >=, for example:
->whereDate('date', '>=', Carbon::now('Europe/Stockholm'))
Here you can use this:
->where('date', '>=', date('Y-m-d'))
Using whereDate will compare the date only and ignore the time. So your solution will give the records that are at least dating one day later and the records that are in the same day but with later hours will not be included.
If you use >= as suggested in other answers, you will get records starting from the current date and those ones who are even before the determined hour.
One solution for this is comparing using MySQL functions in whereRaw. In your code the condition for the date will be like this:
-> whereRaw("date > STR_TO_DATE(?, '%Y-%m-%d %H:%i:%s')" , Carbon::now('Europe/Stockholm')->format('Y-m-d H:i'));
In the code, I changed the format of Carbon date to match a specific format where you can use whatever format you want and put the same format in the STR_TO_DATE function.
For Laravel's TestCases:
$this->assertDatabaseHas('my_table', [
'name' => $name,
[ 'updated_at', '>=', $updatedAt ] // $updatedAt is a Carbon object
]);
I'm using Laravel Framework.
I want all of the rows for this day. This is what I tried:
DB::table('users')->where('created_at', '>=', date('Y-m-d H:i:s'))
(field created_at represented in database in format: Y-m-d H:i:s).
Hmmm...there was a good answer to this question which seems to have now disappeared.*
It was something like this:
User::where('created_at', '>=', new DateTime('today'))
Note: if you're putting this code in a file with a namespace, or might use a namespace in the future, you should prefix the DateTime class with a backslash: new \DateTime('today').
*
https://stackoverflow.com/questions/15052679/laravel-framework-how-to-get-today-queries
date('Y-m-d H:i:s') returns date of now.
If you want results from start of the day you can replace it with date('Y-m-d').' 00:00:00'.
If you want results from last 24 hours you can replace it with date('Y-m-d H:i:s',time()-86400) (86400 = 24*60*60)
For those who only need to compare a date without time, Lavarel provided a handy function whereDate:
User::whereDate('created_at', '>=', date('Y-m-d'));
http://laraveldaily.com/eloquent-date-filtering-wheredate-and-other-methods/
I know that topic is old but may someone try to find a solution from search engines.
You can use:
User::whereDate('created_at', '=', Carbon::today()->toDateString());
You can visit this link if you want to know more about date comparison in Laravel using where.
Eloquent date filtering: whereDate() and other methods
Simply:
DB::table('users')->where('created_at', '>=', date('Y-m-d'). ' 00:00:00')
When getting all rows for this day(the time should be 00:00:00), so make sure to set the date condition to current date plus 00:00:00 i.e.
date('Y-m-d'). ' 00:00:00'
Use whereDate
$users = DB::table('users')
->whereDate('created_at', '2016-12-31')
->get();
other functions you may use are: whereDate / whereMonth / whereDay / whereYear / whereTime