Hope all are doing well. I need to print an array as time slots.
Assume that there are 2 orders for 2021.11.15 on 11:30am to 12:00pm and 2:00pm to 4:15pm.
My order needs 1h 30m to complete. Therefore time slots should be in between 8:00am and 6:00pm skipping those times for already exist orders.
My expected results should be:
array:2 [
0 => array:2 [
"start" => "08:00:00"
"end" => "9:30:00"
]
1 => array:2 [
"start" => "09:30:00"
"end" => "11:00:00"
]
2 => array:2 [
"start" => "12:00:00"
"end" => "13:30:00"
]
3 => array:2 [
"start" => "16:15:00"
"end" => "17:45:00"
]
]
Following line is used to get exist orders object with their start and end times.
$existOrders = $this->orderHasPropartnerService->getOrderExistForDateProPartner($proPartnerDefaultLocation->id, $selectedDateRecord->date);
Then I just looped it.
if ($existOrders->count() > 0) {
$dateStartTime = $selectedDateRecord->time_from;
$x = 0;
$firstEndingTime = Carbon::parse($dateStartTime)->addMinutes($totalTimeToOrder)->format('H:i:s');
foreach ($existOrders as $key1 => $existOrder1) {
if ($existOrder1->order->time_slot_from < $firstEndingTime && $existOrder1->order->time_slot_to >= $firstEndingTime) {
$timeCheckArray[$x]['start'] = $existOrder1->order->time_slot_to;
$timeCheckArray[$x]['end'] = Carbon::parse($existOrder1->order->time_slot_to)->addMinutes($totalTimeToOrder)->format('H:i:s');
} else {
$timeSlotArray[$x]['start'] = $dateStartTime;
$timeSlotArray[$x]['end'] = $firstEndingTime;
$timeCheckArray[$x]['start'] = $firstEndingTime;
$timeCheckArray[$x]['end'] = Carbon::parse($firstEndingTime)->addMinutes($totalTimeToOrder)->format('H:i:s');
}
if (isset($existOrders[$key1+1])) {
if ($existOrders[$key1+1]->order->time_slot_from < $timeCheckArray[$x]['end'] && $existOrders[$key1+1]->order->time_slot_to >= $timeCheckArray[$x]['end']) {
} else {
$timeSlotArray[$x+1]['start'] = $timeCheckArray[$x]['start'];
$timeSlotArray[$x+1]['end'] = $timeCheckArray[$x]['end'];
}
}
}
}
As for the above example $dateStartTime will be 8:00am. Value of $totalTimeToOrder will be 1h 30m.
When I try to print $timeSlotArray it'll result as follows:
array:2 [
0 => array:2 [
"start" => "08:00:00"
"end" => "09:30:00"
]
1 => array:2 [
"start" => "08:00:00"
"end" => "09:30:00"
]
]
It is really appreciated if someone point me out where I did mistakes in this logic. Thank you so much guys for your valuable time for a problem of mine.
The best approach would be to run a for loop to check that the New order does not fall between the booked times .
Try something similar to this by converting it to a PHP Date object
$NewOrder= "4:59 pm";
$start= "5:42 am";
$end= "6:26 pm";
$date1 = DateTime::createFromFormat('h:i a', $NewOrder);
$date2 = DateTime::createFromFormat('h:i a', $start);
$date3 = DateTime::createFromFormat('h:i a', $end);
if ($date1 > $date2 && $date1 < $date3)
{
echo 'Not safe to add it ';
}
Related
I have a query to get the number of insertions grouped by months. I have beberlei Doctrine extensions already installed and working, but the array return have the month number as key. How will be used in a chart line, I want to show the month name instead of month number.
What is the best way to do this?
This the query:
//get and format the current year
$date = new \DateTime();
$year = $date->format('Y');
//create query
$qb = $this->_em->createQueryBuilder();
$qb->select(['MONTH(p.createdAt) as month', 'count(ccp) as insertions'])
->from(CareConnectPatient::class, 'ccp')
->join('ccp.person', 'p')
->where('YEAR(p.createdAt) = :year')->setParameter('year', $year);
$qb->groupBy('month');
return $qb->getQuery()->getScalarResult();
And I do that with that result:
`$countMonths = count($cCPatientGroupedByMonth);
for ($count = 0; $count<$countMonths; $count++){
$arrayKeyAsMonth[$cCPatientGroupedByMonth[$count]['month']] = $cCPatientGroupedByMonth[$count]['insertions'];
}`
What gives me something like this:
array:3 [
4 => "1",
8 => "2",
9 => "2"
]
I what to know the best way to make this appear as:
array:3 [
april => "1",
august => "2",
september => "2"
]
Sorry for bad english and thanks!
have you tried using MONTHNAME() function?
instead of:
$qb->select(['MONTH(p.createdAt) as month', 'count(ccp) as insertions'])
try:
$qb->select(['MONTHNAME(p.createdAt) as month', 'count(ccp) as insertions'])
I have below array
$users = [
[ "_createdAt" = > "2020-09-15 12:10:21", "username" => "A"],
[ "_createdAt" = > "2020-09-15 12:08:24", "username" => "B"]
[ "_createdAt" = > "2020-09-15 11:30:45", "username" => "C"]
[ "_createdAt" = > "2020-09-15 11:08:00", "username" => "D"]
];
Step 1 => i have to find current time - 10 minutes
Step 2 => i have to keep the usernames($users array) who has created 10
minutes ago
For exapmple current time is 2020-09-15 12:15:21
expected aswer is
$users = [
[ "_createdAt" = > "2020-09-15 11:30:45", "username" => "C"]
[ "_createdAt" = > "2020-09-15 11:08:00", "username" => "D"]
];
Use array_filter and strtotime function for that.
$tenMinuteOldTime = date('Y-m-d H:i:s', strtotime("-10 minutes"));
$newArray = array_filter($users, function($k) use($tenMinuteOldTime ) {
return $k['_createdAt'] < $tenMinuteOldTime ;
});
So if you are in different timezone and you know how forward and backward that timezone is from GMT, you can just modify the strtotime parameter.
So for example if we take IST that is GMT+5:30. So that is 330 minutes forward and we want data from 10 mins ago, so we can change parameter to 330 -10 = 320 as follow
$tenMinuteOldTime = date('Y-m-d H:i:s', strtotime("+320 minutes"));
Definitely there are other methods to get current time in a given timezone but by seeing the other answer and you're not able to use new DateTime, I suggested this quick fix.
Use array_filter with DateTime.
<?php
// Users array
$users = [
[ "_createdAt" => "2020-09-15 12:10:21", "username" => "A"],
[ "_createdAt" => "2020-09-15 12:08:24", "username" => "B"],
[ "_createdAt" => "2020-09-15 11:30:45", "username" => "C"],
[ "_createdAt" => "2020-09-15 11:08:00", "username" => "D"],
];
// get current dateTime
$currentTime = (new DateTime())->getTimestamp();
// filtering users
$filteredUsers = array_filter($users, function($user) use ($currentTime) {
// convert createdAt from string to date
$createdAt = (new DateTime($user['_createdAt']))->getTimestamp();
// check the difference is >= 10 minutes (600 seconds)
return ($currentTime - $createdAt) >= 600;
});
// display filtered users
var_export($filteredUsers);
?>
I'm trying to pass a test that involves running a query that returns a series of logins to test whether two arrays are equal in the test.
In the past I have tried changing the format of the query to make the test pass as well as editing the arrays and eventually it equalled the two arrays. Unfortunately the test still doesn't pass.
The function that performs the query to get a series of dates of logins:
public function getLogins(): array
{
return $this->createQuery()
->select('date AS datetime, COUNT(id) as total')
->orderBy('datetime', 'DESC')->groupBy('datetime')
->where('date >= -24 hours')
->getQuery()
->getResult();
}
This is the method in the test class:
public function testGetLogins()
{
$dateLogins = $this->repository->getLogins();
$this->assertCount(4, $dateLogins, "Four instances");
$this->assertEquals([
["datetime" => new \DateTime("now -3 minutes"), "total" => "1"],
["datetime" => new \DateTime("now -7 days"), "total" => "1"],
["datetime" => new \DateTime("now -1 year"), "total" => "1"],
["datetime" => new \DateTime("now -600 days"), "total" => "1"]
], $logins, "The login instances returned match the expected times");
}
I'm expecting the test to pass but instead it is displaying this:
Test Output
The expected and actual arrays are both equal so I'm unsure as to what is causing the test to fail.
\DateTime format contains information about seconds as well. new \DateTime("now -3 minutes") will return now minus 3 minutes but exact amount of seconds, which will be always different, depending on the time when you did launch the test. Apparently you want to compare dates till minutes, so you have to format your dates before comparsion, therefore you have to compare each set separately:
$expectedValues = [
["datetime" => new \DateTime("now -3 minutes"), "total" => "1"],
["datetime" => new \DateTime("now -7 days"), "total" => "1"],
["datetime" => new \DateTime("now -1 year"), "total" => "1"],
["datetime" => new \DateTime("now -600 days"), "total" => "1"]
];
for ($i = 0; $i < count($expectedValues); ++$i) {
$actualDate = (new \DateTime($logins[$i]['datetime']))->format('Y-m-d H:i');
$expectedDate = ($expectedValues[$i]['datetime'])->format('Y-m-d H:i');
$this->assertEquals($expectedDate, $actualDate);
$this->assertEquals($expectedValues[$i]['total'], $logins[$i]['total']);
}
So I need to create a sort of day-per-day calendar with available times, in order for a user to be able to book a meeting with one doctor from a cabinet of multiple doctors.
I hope that this explanation is not too weird already..
Btw I use Laravel 5.5
Here's an example:
Default Schedule of the cabinet : 9:00 to 19:00
Doctor 1 says that on monday, he'll be only available from 13:00 to 15:00
Doctor 2 says that on monday, he'll be only available from 10:00 to 14:00
When I query the available timeslots :
$ids = Doctor::all()->pluck('id');
$workingSchedules = WorkingSchedule::whereIn('user_id', $ids)
->orderBy('start_date')
->whereDate('start_date', '=', $this->datetime->format('Y-m-d'))
->get();
I get:
0 => [
"start_date" => "2017-09-18 10:00:00"
"end_date" => "2017-09-18 14:00:00"
]
1 => [
"start_date" => "2017-09-18 13:00:00"
"end_date" => "2017-09-18 15:00:00"
]
And if nothing shows up from the Database then I use the default cabinet hours.
Then I use Carbon diffInMinutes() method to construct an array of 30 minutes timeslots between those date range (that the user can select).
Anyway, for my script to work correcty I need to transform the result I showed you into this:
0 => [
"start_date" => "2017-09-18 10:00:00"
"end_date" => "2017-09-18 15:00:00"
]
As I only have two timeslots in this example it might be simple a solution, but I might also get an array of 10 timeslots that overlapse one another..
Can somebody help me find a elegant solution that will cover all possible case ?
Thanks a lot in advance.
To be easier, I will suppose $workingSchedules is an array of numbers, then we can easily compare elements
$workingSchedules = [
[
'start_date' => 1,
'end_date' => 5,
],
[
'start_date' => 13,
'end_date' => 16,
],
[
'start_date' => 16,
'end_date' => 17,
],
];
$result = [$workingSchedules[0]];
$index = 0;
foreach ($workingSchedules as $row) {
if ($result[$index]['end_date'] >= $row['start_date']) {
$result[$index]['end_date'] = max($result[$index]['end_date'], $row['end_date']);
} else {
$index++;
$result[] = $row;
}
}
var_dump($result);
Above code will print:
[
[
'start_date' => 1,
'end_date' => 5,
],
[
'start_date' => 13,
'end_date' => 17,
],
]
You can custom the code to compare 2 dates instead numbers
If $workingSchedules is empty, we can simply return default schedule
To merge overlapping time-periods, you could use this code:
$result = [];
$i = -1;
foreach ($workingSchedules as $row) {
if ($i < 0 || $row["end_date"] > $result[$i]["end_date"]) {
if ($i >= 0 && $row["start_date"] <= $result[$i]["end_date"]) {
$result[$i]["end_date"] = $row["end_date"];
} else {
$result[++$i] = $row;
}
}
}
$result will then have non-overlapping periods only.
I hope this will help.
$workingSchedules=array(
0=>array(
"start_date" => "2017-09-18 10:00:00",
"end_date" => "2017-09-18 14:00:00"),
1=>array(
"start_date" => "2017-09-18 13:00:00",
"end_date" => "2017-09-18 15:00:00"
)
);
foreach ($workingSchedules as $schedule){
$start=new DateTime($schedule['start_date']);
$end=new DateTime($schedule['end_date']);
while ($start<=$end){
echo $start->format('Y-m-d H:i')."<br/>";
$start=$start->add(new DateInterval('PT'.'30'.'M'));
}
}
I'm currently using the Gravity Forms plugin and it's set up to limit form entries per day, week, month and year; unfortunately, I need it by hour. Here is the original code that I'm editing:
private static function get_limit_period_dates($period){
if(empty($period))
return array("start_date" => null, "end_date" => null);
switch($period){
case "day" :
return array(
"start_date" => gmdate("Y-m-d"),
"end_date" => gmdate("Y-m-d 23:59:59"));
break;
case "week" :
return array(
"start_date" => gmdate("Y-m-d", strtotime("Monday this week")),
"end_date" => gmdate("Y-m-d 23:59:59", strtotime("next Sunday")));
break;
case "month" :
$month_start = gmdate("Y-m-1");
return array(
"start_date" => $month_start,
"end_date" => gmdate("Y-m-d H:i:s", strtotime("{$month_start} +1 month -1 second")));
break;
case "year" :
return array(
"start_date" => gmdate("Y-1-1"),
"end_date" => gmdate("Y-12-31 23:59:59"));
break;
}
}
I've attempted the following code, I figured starting at 0 minutes and 0 seconds, then adding an hour would do the trick, but it isn't working:
case "hour" :
return array(
"start_date" => gmdate("H:00:00"),
"end_date" => gmdate("H:i:s", strtotime("+1 hour")));
break;
I've never used the gmdate function, so I'm eager to get a grasp on this if someone's willing to briefly explain what I'm missing. Thanks!
I think this might be what you want:
case "hour" :
$hour_start = gmdate("Y-m-d H:00:00");
return array(
"start_date" => $hour_start,
"end_date" => gmdate("Y-m-d H:i:s", strtotime("{$hour_start} +1 hour")));
break;
You have to do 1 hour after the start hour. Otherwise it takes it as 1 hour from now.