How to search a range of dates between another range with Laravel? - php

I'm pretty new to using Laravel, but I've managed to create a pretty basic API. I'm starting to try and add filters to the API, and the primary filter I need is to see if a date range overlaps another date range.
For example, here is a typical data object returned from my database:
{
id: 1,
name: 'This is the name',
start_date: '2017-01-03',
end_date: '2017-01-29'
}
The users would typically filter by a smaller date range. For example, give me results whose start and end range fall between 2017-01-28 and 2017-02-04.
So something like:
data start data end
|------------------------|
|----------------|
search start search end
Throughout my research, I can only find answers relating to searching if a single date falls in a range, not if any part of a range falls inside another range.
This is what I currently have:
$closures = Closures::where('start_date', '>=', $from)->where('end_date', '<=', $to)->get();
The problem with this approach is that it doesn't really account for partial overlaps. In the above example, my search date is indeed greater than or equal to the data's, but since the end date is actually greater than the data's end date, it will not be returned.
The obvious would be to make the second stipulation and orWhere, but then that returns literally all data with a less than date which does not work.
I basically need to check if any part of of my search range falls within the data's range. Is this even possible, if so, any ideas on how I could achieve this.

You would check to see if any of the 2 dates provided falls between a range in your data. I would use nested wheres to avoid any logic spill over.
$closures = Closures::where(function($query) use ($start) {
return $query->where('start_date', '<=', $start)->where('end_date', '>=', $start);
})
->orWhere(function($query) use ($end) {
return $query->where('start_date', '<=', $end)->where('end_date', '>=', $end);
})
->get();

Related

Laravel query builder count rows by day SQL db::raw

I've got a Laravel 8 application whereby I need to count the number of total applications for each day and output a count of the data in the most efficient way, for instance, 500 applications on 1st, 1,000 applications on 2nd and so fourth, depending on how many applications there are each day.
I'm using DB::raw() to count my rows, however, Laravel's timestamps by default includes the hours, minutes and seconds as part of the date, and so this isn't going to work for me, I need to format the date to exclude this and just contain the day.
My query doesn't seem to be returning anything, and no error either, so I think there's something wrong with my first DB::raw(), it doesn't seem to be formatted the created_at column at all, what am I missing?
Application::whereBetween('created_at', [$from, $to])
->select(DB::raw('DATE_FORMAT("created_at, %Y-%m-%d")'), DB::raw('count(*) as applications'))
->groupBy('created_at')
->get();
You can use groupByRaw()
Application::whereBetween('created_at', [$from, $to])
->select(DB::raw('DATE_FORMAT(created_at, "%Y-%m-%d")'), DB::raw('count(*) as applications'))
->groupByRaw('DATE_FORMAT(created_at, "%Y-%m-%d")')
->get();
Also, you can use selectRaw() instead of select(DB::raw)

How can I get all records for the week using date strings not date objects?

I have a table in the database where the records contain a start_date and an end_date. An example of the data format is:
"13/03/2020"
How can I fetch all records for the week? I have tried the code below. However, it does not return any data.
$date = Carbon::now()->format('d/m/Y');
$dateInWeek = Carbon::now()->addDays(7)->format('d/m/Y');
$holidays = Holiday::where('start_date', '>=', $date)
->where('end_date', '<=', $dateInWeek)->get();
Probably correct solution is to change string to datetime in db, if it is not an opinion then you can create custom function in database that will handle strings in way you want.
You shouldn't use string when you can use date / datetime column type.
But that being said - it's not always up-to us to be able to change DB structure.
Solution 1
Depending on what SQL you are using there is usually function to cast string to date.
For example MySQL: STR_TO_DATE(string, format)
https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_str-to-date
Solution 2
You can make array containing all dates of week using Carbon.
then in query: ->whereIn('start_date', $datesArray)->whereIn('end_date', $datesArray)
I'd still suggest changing column type to date if possible

Laravel eloquent grabbing results between two days

I have a model for which I have a database field called day. This is a unique field and it can contain a day like monday, tuesday, and so on. So monday can only be used once, etc. The value is literally stored as a string.
Now I am trying to display only upcoming x results, for example, only the results from the next 3 days. Which means, I want to display the result of today, tomorrow and the day after tomorrow. I have been trying like below:
Model::where('day', '>=', Carbon::now())
->where('day', '<', Carbon::now()->addDays(3))
->get();
But this does not give me any results. I want to prevent having to change the field to a date field, for now. But I was wondering if there is any way to achieve what I am looking for with a simple eloquent query.
if the day is unique you can get the next three days and select their results:
$today=Carbon::now()->dayName;
$tomorrow=Carbon::tomorrow()->dayName;
$afterTomorrow=Carbon::tomorrow()->addDay()->dayName;
$acceptableDays=[$today,$tomorrow,$afterTomorrow];
Model::whereIn('day', $acceptableDays)
->get();
pay attention to letter case, Carbon::now()->dayName; will gave you the day name with first capital letter, you should convert it to match the way it stored in your db

Laravel: whereBetween to accept the first date

Scenario:
The startdate and enddata in the database is 2015-07-20 and 2015-07-30 respectively and the query that works properly is,
Model::whereBetween('startdate',array('2015-07-30','2015-08-10'))->get();
The query return 1 record from the table which is the expected result. Now what I expect is a slight change. The query should not retrieve the record by considering the date 2015-07-30 does not fall in between 2015-07-30. How do I achieve this?
whereBetween is inclusive. In order to exclude one of the edges you'll need to build a between query manually:
Model::where('startdate', '>', '2015-07-30')->where('startdate', '<=', '2015-08-10')->get();
Easy Solution
Model::whereBetween(DB::raw('date(startdate)'),array('2015-07-30','2015-08-10'))->get();

Laravel 5 / Carbon: Count number of records for specific range in a different timezone

I store my records in EST timezone rather than UTC as I almost never need to use UTC. Recently though I have needed to generate a report in UTC.
I count the number of "clicks" on my site, this is how I grab yesterdays click total:
Click::where('created_at', '>=', Carbon::now()->yesterday())->where('created_at', '<=', Carbon::now()->startOfDay())->count();
That works great, but now I need to get the click total for "yesterday in UTC" -- is there an easy way to do this using eloquent / carbon?
Assuming that your records in your database are stored as EST as you mention then you will need to do the following.
// Get the start and end times you want in UTC
$start = Carbon::yesterday('UTC');
$end = Carbon::yesterday('UTC')->endOfDay();
// Convert those times to EST
$start->timezone('EST');
$end->timezone('EST');
// Now query the number of clicks, 'whereBetween' is a great little shortcut
// for querying over a range
Click::whereBetween('created_at', [$start, $end])->count();
Note that carbon is a fluent API so you could simplify this to;
$start = Carbon::yesterday('UTC')->timezone('EST');
$end = Carbon::yesterday('UTC')->endOfDay()->timezone('EST');
Depends entirely how you want your code to read.
As an aside the Carbon::now() and
Carbon::yesterday() builders will use the default timezone specified in your php.ini if it is not supplied.

Categories