Laravel carbon retrieve record even when it shouldn't - laravel

I am searching by start and end date or with a weekday, which kind of works fine however if weekday is equal to 'WE' and today's weekday is equal to 'WE' it still brings back results even when $today date is < than endate.
public function show($id)
{
$weekMap = [
0 => 'SU',
1 => 'MO',
2 => 'TU',
3 => 'WE',
4 => 'TH',
5 => 'FR',
6 => 'SA',
];
$todayWeek = Carbon::now()->dayOfWeek;
$today= Carbon::now();
$weekday = $weekMap[$todayWeek];
$event = Event::with('businesses')
->where('startdate', '<', $today->format('Y-m-d'))
->where('endate', '>', $today->format('Y-m-d'))
->orWhere('weekday', '=', $weekday)
->get();
dd($event);
return view('events.showEvent', compact('event'));
}
If I change orWhere to where, results are all good, however user not always enters a weekday so it can be empty. I want it to work like this:
output everything where startdate < today and where endate > today and if weekday is not empty, output everything where startdate < today, endate > today and weekday = $weekday. I hope that makes sense.
//edit
sample data:
data
So what I want is really search by frequency so it would look like this:
if frequency = daily
compare start and end with today's date.
if frequency = weekly
compare start and end with today's date and weekday.
bring back all results for frequency = daily+weekly

you can use if condition in query like this:
$query = Event::with('businesses')
->where('startdate', '<', $today->format('Y-m-d'))
->where('endate', '>', $today->format('Y-m-d'));
if ($weekday != '') {
$query->where('weekday', $weekday);
}
$event = $query->get();
also
condition if ($weekday != '') check $weekday isset or not you can use
if ( ! is_null($weekday )) instead

Related

How to get last 7 days records with 0 counts

I have an eloquent query that gets the total count records (created_at) of the last 7 days. But the problem is if one of these days have 0 records, this doesn't appear in the final data.
My query:
$data = Data::whereBetween('created_at', [Carbon::now()->subDays(6)->format('Y-m-d')." 00:00:00", Carbon::now()->format('Y-m-d')." 23:59:59"])
->groupBy('date')
->orderBy('date')
->get([
DB::raw('DATE(created_at) as date'),
DB::raw('count(*) as total')
])
->pluck('total', 'date')->toArray();
What I get:
[
"2020-04-14" => 1
"2020-04-16" => 1
"2020-04-18" => 1
"2020-04-19" => 1
]
What I expected:
[
"2020-04-14" => 1
"2020-04-15" => 0
"2020-04-16" => 1
"2020-04-17" => 0
"2020-04-18" => 1
"2020-04-19" => 1
"2020-04-20" => 0
]
Any suggestions?
SOLUTION:
-Based on Gary Houbre's proposal:
$results = Data::whereBetween('created_at', [Carbon::now()->subDays(6)->format('Y-m-d')." 00:00:00", Carbon::now()->format('Y-m-d')." 23:59:59"])
->groupBy('date')
->orderBy('date')
->get([
DB::raw('DATE_FORMAT(created_at, "%Y-%m-%d") as date'),
DB::raw('count(*) as total')
])
->keyBy('date')
->map(function ($item) {
$item->date = Carbon::parse($item->date);
return $item;
});
$period = new DatePeriod(Carbon::now()->subDays(6), CarbonInterval::day(), Carbon::now()->addDay());
$graph = array_map(function ($datePeriod) use ($results) {
$date = $datePeriod->format('Y-m-d');
return $results->has($date) ? $results->get($date)->total : 0;
}, iterator_to_array($period));
Looking directly Sql : How to include "zero" / "0" results in COUNT aggregate?
Into a same table : How to get the record if Count is zero in Laravel
You need to add an outer join into your request with Eloquent.
My idea is to create a for loop to check the days.
If there is no record on a date then print 0
Loop Iteration:
Catch the first Day (Suppose 14)
Catch the last Day
Then check in every iteration it is greater than one or many
Thus, I hope you will get normally.
We had a similar problem while trying to put back-end data into the chart. Since some of the days were missing it didn't look well. Our solution was;
Create a function like this;
public function generateDates(Date $startDate, Date $endDate, $format = 'Y/m/d'): Collection
{
$dates = collect();
$startDate = $startDate->copy();
for ($date = $startDate; $date->lte($endDate); $date->addDay()) {
$dates->put($date->format($format), 0);
}
return $dates;
}
In your case it's going to be (today and today - six days) and you will union returning collection with your query collection. What it does is; it create a date range from the keys and fill them with zero. When your query collection has some value other than zero - it is going to overwrite it.

Display total days between two dates if status is completed

I am trying to count the number of days between two dates the carbon::now and $start_date and when the status == complete the counting of days stops then get the total number of days.
if ($this->status === 'COMPLETED') {
$now = Carbon::now();
$start_date = Carbon::createFromFormat('Y-m-d', $this->start_date);
$this->start_date_to_current_date = $start_date->diffInDays($now, true);
}
But the problem is, the days still continues to count even the status is completed like for example the total days is 3 then in the next day it becomes 4 then ive tried doing this:
if ($this->status == null && $this->status === 'COMPLETED') {
$now = Carbon::now();
$start_date = Carbon::createFromFormat('Y-m-d', $this->start_date);
$this->start_date_to_current_date = $start_date->diffInDays($now, true);
}
But the value becomes zero. why is that ? :/
You need to log the complete date somewhere, and use it instead of now().
For instance:
if ($this->status === 'COMPLETED') {
$start_date = Carbon::createFromFormat('Y-m-d', $this->start_date);
$start_date->diffInDays($this->completed_date); // completed_date should come from db.
}
The problem here is that you're using the current date as complete date which is obviously changing everyday, hence you get different result each day.
let it only do that when you not yet, and do not repeat do it.
`if ($this->status == null && $this->status !== 'COMPLETED') {`
`$now = Carbon::now();`
`$start_date = Carbon::createFromFormat('Y-m-d', $this->start_date);`
`$this->start_date_to_current_date = $start_date->diffInDays($now, true);`
}

Dates comparision not working on my codeigniter model class

$today=date('y-m-d');
$query3 = $this->db->query("SELECT exp_date FROM other_data WHERE id_usr ='$session_id' AND status = 1")->row()->exp_date;
if($query3>=$today){
$lndate =array(
'visits' => $query2 + 1 ,
'login_date' => $today
);
$this->db->update('other_data', $lndate);
}
Here exp_date is a date which is in the same format as $today(date).
Even exp_date > today is false the update statement executes in the model
function of codeIgniter. But it should not execute when the condition is wrong.
The date format matched with database date.
Thanks in advance for the help!
Try like this
$today = date('Y-m-d', strtotime('now')); //Current Date
And make date format same as $today have like this
If your are getting date from database.
After getting the record from the database
$query3 = date('Y-m-d', strtotime($query3));
if($query3 >= $today){
//Condition true
}else{
//Condition false
}

Laravel avoid overlapping dates

I am new to Laravel and am trying to implement reservation dates that can not overlap on any day.
I have a model called 'Bookings' that includes the room_id, start_date and end_date.
I have validation that checks that the end date can not be before the start:
$this->validate($request, [
'start_date' => 'required|date',
'end_date' => 'required|date|after_or_equal:start_date',
]);
However I am not sure how to check that the date range does not conflict with any other date ranges of the same room_id stored in the bookings table (as one room can not be booked twice in the same range).
Any help would be appreciated,
Thanks!
In a typical overlaping, given two events A and B, you have to consider four scenarios:
Event A contains event B
Event B contains event A
End date of event A overlaps with start date of event B
End date of event B overlaps with start date of event A
So, in sql to check if a room is busy in a interval of dates, lets say 2018-11-20' and '2018-11-30' it would be:
select *
from rooms
where
start_date between '2018-11-20' and '2018-11-30' or
end_date between '2018-11-20' and '2018-11-30' or
'2018-11-20' between start_date and end_date or
'2018-11-30' between start_date and end_date;
In laravel what I do is to create a scope in the model.
public function scopeByBusy($query,$start_date,$end_date)
{
return $query->whereBetween('start_date', [$start_date, $end_date])
->orWhereBetween('end_date', [$start_date, $end_date])
->orWhereRaw('? BETWEEN start_date and end_date', [$start_date])
->orWhereRaw('? BETWEEN start_date and end_date', [$end_date]);
}
Finally, I can verify if the room with the id 95 is busy between '2018-11-20' and '2018-11-30' like this:
$room_id = 95;
$start = '2018-11-20';
$end = '2018-11-30';
$exists = Rooms::where('id', $room_id)
->byBusy($start, $end)
->first();
if($exists)
{
echo "the room is busy in the interval you selected";
}
I hope it helps you.
I had a similar usage where i needed to check if person has already scheduled something in date range
An example laravel code below :
$start = Carbon::parse($request['start_date'])->format('Y-m-d 00:00:00');
$end = Carbon::parse($request['end_date'])->format('Y-m-d 23:59:59');
$existsActive = Microsite::where(function ($query) use ($start) {
$query->where('start_date', '<=', $start);
$query->where('end_date', '>=', $start);
})->orWhere(function ($query) use ($end) {
$query->where('start_date', '<=', $end);
$query->where('end_date', '>=', $end);
})->count();
if($existsActive > 0 ){
echo "Already exists";
}
There's built-in Carbon method isPast() so you can use:
$start_date->isPast()
$end_date->isPast()
You can check If both selected were booked in past.
If you haven't used Carbon this is the link:
https://carbon.nesbot.com/docs/
if(DB::table('rooms')->whereBetween('start_date', [$request->start_date, $request->end_date])
->orwhereBetween('end_date',[$request->start_date, $request->end_date])->exists())
{
echo "the room is busy in the interval you selected";
}
You have to check that in database. So you can do this:
$result = Bookings::where('start_date', '<=' $request->start_date)->where('end_date', '>=' $request->end_date)->where('room_id',$request->room_id)->first();
if(!$result){
// Code to Book room
}

how to get all products between two dates?

how to get all products between two dates like last month products, this month products , last week products and this week products etc.
i tried with this:
// current day to start with
$start = mktime(0,0,0,date('m'), date('d'), date('Y'));;
// calculate the first day of last month
$first = date('YYYY-MM-DD',mktime(0,0,0,date('m',$start) - 1,1,date('Y',$start)));
// calculate the last day of last month
$last = date('YYYY-MM-DD',mktime(0, 0, 0, date('m') -1 + 1, 0, date('Y',$start)));
if($filter == "lastmonth"){
$collection = Mage::getModel('catalog/product')->getCollection();
$collection->addAttributeToFilter('updated_at', array('gteq' =>$first));
$collection->addAttributeToFilter('updated_at', array('lteq' => $last));
}
but i am not able to get the result :( any help ?
Modified after Daniel response !
1) First of all you need to change you date formate from 'YYYY-MM-DD' to 'Y-m-d'. This will return a date formate which magento records have.
2) There is a special condition for date as bellow mention with your example.
$collection = Mage::getModel('catalog/product')->getCollection();
$collection->addAttributeToFilter('updated_at', array('gteq' =>$first));
$collection->addAttributeToFilter('updated_at', array('lteq' => $last));
To.
$collection = Mage::getModel('catalog/product')->getCollection();
$collection->addAttributeToFilter('updated_at', array(
'from' => $first,
'to' => $last,
'date' => true,
));
I tried your code and had to swap 'lteq' and 'gteq' to make it work. The $fromdate is the lower number so you are searching for dates greater than that number.
Also you must remember to format the dates as MySQL likes it; date('Y-m-d').
PS. See the comparison operators for a full list
There is one issue with your code:
$collection->addFieldToFilter()
should be:
$collection->addAttributeToFilter()
I know that the question is little bit old but as it is quite well ranked in search engine results, I will correct the date() function that better take as arguments something like : Y-m-d H:i:s.
I hope it will help !

Resources