Find records between two time slots in php - php

i have time slots like
$timeslot = ['09:00-10:00', .... '23:00-00:00', '00:00-01:00'];
I have records with updated time as 23:15:00, 23:30:00, 00:15:00, 09:15:00 etc.
What i'm trying to find is the sum of records between each of the $timeslot. I'm not considering what day got updated, only time i'm looking for.
i tried with:-
$data = ['23:15:00', '23:30:00', '00:15:00', '09:15:00'];
foreach($data as $val) {
$cnt = 0;
foreach($timeslot as $slots) {
$slot = explode("-", $slots);
if( (strtotime($val) > strtotime($slot[0])) && (strtotime($val) <= strtotime($slot[1])) ) {
$up_time[$slot[0] . '-' . $slot[1]] = $cnt++;
}
}
}
echo '<pre>';print_r($up_time);echo '</pre>';
The expected output is:-
09:00-10:00 = 1
23:00-00:00 = 2
00:00-01:00 = 1

Strtotime is not required since your time can be compared as strings.
This code works as you expected.
$data = ['23:15:00', '23:30:00', '00:15:00', '09:15:00'];
$timeslot = ['09:00-10:00', '23:00-00:00', '00:00-01:00'];
$up_time = array();
foreach ($data as $val) {
$myTime = substr($val, 0, 5);
foreach ($timeslot as $slot) {
$times = explode("-", $slot);
if (substr($times[1], 0, 3) == "00:") {
$times[1] = "24:" . substr($times[1], 3);
}
if ($myTime >= $times[0] && $myTime <= $times[1]) {
if (!isset($up_time[$slot])) {
$up_time[$slot] = 1;
} else {
$up_time[$slot]++;
}
}
}
}
echo '<pre>';
print_r($up_time);
echo '</pre>';
The if with 'substr' is needed because for midnight you have '00' and not '24' so the computer thinks is an empty set (such as hours bigger then 23 and smaller then 0).
Comparison is made between string because bigger time is also a bigger string since you use 2 digits for hours.
You need to count equal slots so you need an array with an element for each slot and increment if duplicate or create an element if not found (the condition '!isset').
Update for modification request
$data = ['23:15:00', '23:30:00', '00:15:00', '09:15:00'];
// added unused slot 8:00-9:00
$timeslot = ['08:00-09:00','09:00-10:00', '23:00-00:00', '00:00-01:00'];
$up_time = array();
// new initialization
foreach ($timeslot as $slot) {
$up_time[$slot] = 0;
}
foreach ($data as $val) {
$myTime = substr($val, 0, 5);
foreach ($timeslot as $slot) {
$times = explode("-", $slot);
if (substr($times[1], 0, 3) == "00:") {
$times[1] = "24:" . substr($times[1], 3);
}
if ($myTime >= $times[0] && $myTime <= $times[1]) {
$up_time[$slot]++; // simplified
}
}
}

Related

Counting tickets by hour in Laravel

I'm trying to create hourly counting groups of tickets. I have to count three tickets for each hour and insert them as a bonus while inserting the remaining ones as a malus; every hour perform this count on a table where tickets are generated. I should calculate based on two time periods, one from 7 in the morning to 15 in the afternoon and one from 15 in the afternoon to 7 in the morning. I was taking a cue from this post, but I can't see the ticket number and time, while I can see the down, up, total and uptime columns. Can anyone help me perform this? I would also like to insert the count of time between the opening and closing of each intervention
Laravel group data by odd amount of hours throughout days
$uptimeData = Ticket::whereYear('created_at', '>=', Carbon::now()->year)
->whereYear('created_at', '<=', Carbon::now()->year)
->orderBy('created_at', 'asc')
->select('ticket_Id', 'created_at')
->get();
$intervals = \Carbon\CarbonInterval::hours(1)->toPeriod('2023/01/01 07:00:00', '2023/01/01 15:00:00');
$uptimeDataTimeline = $uptimeData->groupBy(function ($item, $key) use ($intervals) {
$date = Carbon::parse($item->created_at);
foreach ($intervals as $key => $interval) {
if ($date->hour == Carbon::parse($interval)->addHours(1)->hour) {
$actualHour1 = Carbon::parse($interval)->hour;
if (strlen($actualHour1) == 1) {
$actualHour1 = "0$actualHour1";
}
return $date->format("Y-m-d $actualHour1:00:00");
} else {
if ($date->hour == Carbon::parse($interval)->addHours(1)->hour) {
$actualHour2 = Carbon::parse($interval)->subHours(1)->hour;
if (strlen($actualHour2) == 1) {
$actualHour2 = "0$actualHour2";
}
return $date->format("Y-m-d $actualHour2:00:00");
}
}
}
return $date->format('Y-m-d H:00:00');
});
$uptimeDataTimeline = $uptimeDataTimeline->map(function ($checksInPeriod, $key) {
$down = 0;
$up = 0;
$total = 0;
$uptime = 0;
$fill = '#1fc777';
foreach ($checksInPeriod as $key => $value) {
$total++;
if ($total <= 3) {
$up++;
} else {
$down++;
}
}
$uptime = floatval(number_format(round($up / $total, 5) * 100, 2, '.', ','));
if ($uptime < 100) {
$fill = '#9deab8';
}
if ($uptime < 99) {
$fill = '#fbaa49';
}
if ($uptime < 98) {
$fill = '#e0465e';
}
return [
'total_ticket_Id' => $total,
'down_ticket_Id' => $down,
'up_ticket_Id' => $up,
'uptime' => $uptime,
'fill' => $fill,
];
});

when I use For loop, key pass the next step. while the foreach data did not changed data.PHP

This is my function, which to calculate the intersection time range of two people. when I use three loops, the first loop could pass the key to the next step, but the data they used belong to other people's data. I am very confused.
public function test()
{
//choose records of viva arrangement
$records = DB::table('application_student')
->where('allocationStatus', '=', 1)
->select('user_id', 'supervisor_id', 'assessor_id')
->get()->toArray();
//single records
foreach ($records as $key => $record) {
$viva[] = [
$sup_id = $record->supervisor_id, // key 0=>supervisor
$stu_id = $record->user_id, // key 1=>student
];
}
// $x is the key number of viva[]
for ($x = 0; $x <count($records); $x++){
$sup_id = $viva[$x][0]; //supervisor_id of record $x
$stu_id = $viva[$x][1]; //student_id of record $x
//find availability of supervisor
$sup_time = DB::table('time_allocates')
->where('user_id','=',$sup_id)
->select('start','end')->get()->toArray();
//find availability of student
$stu_time = DB::table('time_allocates')
->where('user_id','=',$stu_id)
->select('start','end')->get()->toArray();
//every single availability of supervisor
foreach ($sup_time as $key => $supT) {
$sup[] = [
$s1 = strtotime($supT->start), //key 0=>start time
$e1 = strtotime($supT->end), //key 1=>end time
];
}
//every single availability of student
foreach ($stu_time as $key => $stuT) {
$stu[] = [
$s2 = strtotime($stuT->start), //key 0=>start time
$e2 = strtotime($stuT->end), //key 1=>end time
];
}
//$i is the key number of single supervisor availability record
for ($i = 0; $i < count($sup_time); $i++) {
//$j is the key number of single student availability record
for ($j = 0; $j < count($stu_time); $j++) {
echo "$x+'$i'+'$j <br>";
$sup_s1 = $sup[$i][0]; // start time of supervisor
$sup_e1 = $sup[$i][1]; // end time of supervisor
$stu_s2 = $stu[$j][0]; // start time of student
$stu_e2 = $stu[$j][1]; // end time of student
//make sure the time range of student between supervisor has intersection
if($stu_s2>=$sup_s1 && $sup_e1>$stu_s2){
$start = $stu_s2;
if ($sup_e1<=$stu_e2){
$end = $sup_e1;
}else{
$end =$stu_e2;
}
if ($end-$start>=3600){
$start_date = date('Y-m-d H:i:s', $start);
$end_date = date('Y-m-d H:i:s', $end);
echo "$start_date '-' $end_date -$stu_id -$sup_id<br>";
}
}elseif ($sup_s1>=$stu_s2 && $sup_e1>$stu_s2){
$start =$sup_s1;
if ($sup_e1<=$stu_e2){
$end=$sup_e1;
}else{
$end=$stu_e2;
}
if ($end-$start>=3600){
$start_date = date('Y-m-d H:i:s', $start);
$end_date = date('Y-m-d H:i:s', $end);
echo "$start_date '-' $end_date -$stu_id-$sup_id <br>";
}
}
}
}
}
}
this is the result of the window. the student id changed from 2 to 3, but the data use the 2 always. please help me, guys.
enter image description here
You're not reinitializing $sup for each loop.
$sup[] = [
$s1 = strtotime($supT->start), //key 0=>start time
$e1 = strtotime($supT->end), //key 1=>end time
];
Same for $stu[]
for the second student, it will add the data on top of those of the first one.
You need to do it like this
//every single availability of supervisor
$sup = [];
foreach ($sup_time as $key => $supT) {
$sup[] = [
$s1 = strtotime($supT->start), //key 0=>start time
$e1 = strtotime($supT->end), //key 1=>end time
];
}
//every single availability of student
$stu = [];
foreach ($stu_time as $key => $stuT) {
$stu[] = [
$s2 = strtotime($stuT->start), //key 0=>start time
$e2 = strtotime($stuT->end), //key 1=>end time
];
}
PS: you have a lot of redundant code and many extra loops to remove.

How to get the label in the result of an array

The following code works as expected to get the number of patients per age group.
It also gets the highest (or most common) age group.
$count_0_19 = 0;
$count_20_29 = 0;
$count_30_39 = 0;
$count_40_49 = 0;
$count_50_59 = 0;
$count_above_60 = 0;
$curr_year = date('Y');
$sql= "SELECT pt_dob FROM ptlist WHERE mid=$userID";
$stmt = $pdo->query($sql);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$result = $pdo->query($sql);
$pt_dob = $row[ 'pt_dob' ];
while($row = $result->fetch(PDO::FETCH_ASSOC)) {
$pt_dob = explode('-', $row['pt_dob']);
$year = $pt_dob[0];
$month = $pt_dob[1];
$day = $pt_dob
$temp = abs($curr_year - $year);
if($temp >= 0 && $temp <= 19) {
$count_0_19++;
}
elseif($temp >= 20 && $temp <= 29) {
$count_20_29++;
}
elseif($temp >= 30 && $temp <= 39) {
$count_30_39++;
}
elseif($temp >= 40 && $temp <= 49) {
$count_40_49++;
}
elseif($temp >= 50 && $temp <= 59) {
$count_50_59++;
}
else {
$count_above_60++;
}
}
echo '0-19: '.$count_0_19.'<br>';
echo '20-29: '.$count_20_29.'<br>';
echo '30-39: '.$count_30_39.'<br>';
echo '40-49: '.$count_40_49.'<br>'; // example output is > 40-49: 7 (i.e. 7 patients in age group 40-49)
echo '50-59: '.$count_50_59.'<br>';
echo '60+: '.$count_above_60.'<br>';
// getting highest value
$a = array($count_0_19, $count_20_29, $count_30_39, $count_40_49, $count_50_59, $count_above_60);
$res = 0;
foreach($a as $v) {
if($res < $v)
$res = $v;
}
echo $res;
^^ This tells me that e.g. 9 patients are in the 30-39 age group - i.e. the highest number of patients are in this age group.
But $res gives me only the number (e.g. 9).
What I am asking your help with is to get $res to give me the text(or label) "30-39", instead of the number 9.
Please help.
continue from comment... you need to store $key into a variable.
$a = array('0-19'=>$count_0_19, '20-29'=>$count_20_29, '30-39'=>$count_30_39, '40-49'=>$count_40_49, '50-59'=>$count_50_59, '60+'=>$count_above_60);
$res = 0;
$label = '';
foreach($a as $key => $v) {
if($res < $v){
$res = $v;
$label = $key; //get label from key and store in a variable
}
}
echo 'label = '.$label . ' , Number = '.$res;
You can archived this by creating the array of labels and then incrementing it according and then find the greatest value form the $label array to get the key.
$label = [
"0_19" => 0,
"20_29" => 0,
"30_39" => 0,
"40_49" => 0,
"50_59" => 0,
"above_60" => 0,
];
while ($row4 = $result4->fetch(PDO::FETCH_ASSOC)) {
$pt_dob = explode('-', $row4['pt_dob']);
$year = $pt_dob[0];
$month = $pt_dob[1];
$day = $pt_dob$temp = abs($curr_year - $year);
if ($temp >= 0 && $temp <= 19) {
$label['0_19'] = $label['0_19'] +1;
}
elseif ($temp >= 20 && $temp <= 29) {
$label['20_29'] = $label['20_29'] +1;
}
elseif ($temp >= 30 && $temp <= 39) {
$label['30_39'] = $label['30_39']+1;
}
elseif ($temp >= 40 && $temp <= 49) {
$label['40_49'] = $label['40_49'] +1;
}
elseif ($temp >= 50 && $temp <= 59) {
$label['50_59'] = $label['50_59']+1;
}
else {
$label['above_60']= $label['above_60']+1;
}
}
echo $maxs = array_keys($label, max($label));
echo "<br/>";
foreach($label as $k => $v);
echo "key $k count $v <br/>";

How to use regular expression in the WHERE clause of query in Laravel?

I have a table named "Shows". There is a column "show_date". I want to retrieve the shows whose show_date is todays date.
Following is my query
$s = DB::table('shows')->get();
$a = DB::table('shows')->select('show_date')->get();
foreach ($s as $key => $value)
{
$date_test = date('Y-m-d');
$s_test = DB::table('shows')->where('show_date',preg_grep('/"'.$value->show_date.'"./', $a->show_date))->get();
echo "<pre>"; var_dump($s_test);
if(explode(" ",$value->show_date)[0] == date('Y-m-d'))
{
$shows1 = DB::table('shows')->where('id',$value->id)->get();
$s1 = DB::table('transactions')
->select(DB::raw("GROUP_CONCAT(selected_seats SEPARATOR '') as selected_seats"),'userid','amount','show_id')
->where("show_id","=",$value->id)
->groupBy('userid')
->groupBy('amount')
->orderBy('userid','ASC')
->orderBy('amount', 'DESC')
->get();
if($s1 != null)
{
echo $value->id;
$c = count($s1);
$sub_count1 = 0; $next_id = ""; $total_array = 0;
for($i=0;$i<$c;$i++)
{
$first_character = $s1[$i]->selected_seats;
$sub_count = substr_count($s1[$i]->selected_seats, ',');
$sub_count1 = $sub_count1 + $sub_count;//to get the total no. of seats
for($j=0,$k=0;$j<$sub_count;$j++,$k++)
{
// split the string with comma.
$s = explode(',',$first_character);
// get total no. of seat names listed in one row in table.eg A 1,B 2. Then $sub_count would be 2
$p = $s[$j][0];
}
}
// get seats for each show from transaction table.
$demo = DB::table('theater_setting')->select('row_seats_selling_price','row')->where('show_id',$value->id)->get();
foreach ($demo as $key => $val) {
$categoryArr[$val->row]=$val->row_seats_selling_price;
}
$demo4 = DB::table('theater_setting')->select('row_seats_selling_price','row')->where('show_id',$value->id)->get();
$demo3 = DB::table('transactions')->where('show_id',$value->id)->select('selected_seats','userid')->get();
for($p=0;$p<count($demo3);$p++)
{
$arr = explode(',', substr($demo3[$p]->selected_seats,0,-1));
$trans[] = $demo3[$p]->userid;
foreach ($arr as $k => $v)
{
$seats[$demo3[$p]->userid][]=$v;
}
}
foreach ($seats as $user_id=>$v)
{
for ($h=0; $h < count($v); $h++)
{
$e = explode(" ", $v[$h]);
$p = $e[0];
$demo_array[$p][$user_id][] = $v[$h];
}
$users = DB::table('users')->where('id',$user_id)->get();
}
return view('Backend.NewReportByShowsCategory2')->with([
's1'=>$s1,'shows1'=>$shows1,'demo'=>$demo,'categoryArr'=>$categoryArr,'demo3'=>$demo3,'demo4'=>$demo4,'demo_array'=>$demo_array]);
}
else
{
return view('Backend.NewReportByShowsCategory2')->with([
's1'=>$s1]);
}
}
}
I am getting the following error:
Object of class stdClass could not be converted to string
There is alternative way:
DB::table('shows')->where('show_date', 'REGEXP', Carbon\Carbon::now()->toDateString())->get();
You could convert show_date to a DATE and compare it with the current date -
$s_test = DB::table('shows')->whereRaw('DATE(show_date)=CURRENT_DATE')->get()
However, here's the regex query for selecting rows with a particular date (the current date in this case),
DB::table('shows')->whereRaw("show_date REGEXP '". Carbon\Carbon::now()->toDateString() . "'")->get()

Separating an array effectively

I'm having an asbolute nightmare dealing with an array of numbers which has the following structure :
Odd numbers in the array : NumberRepresenting Week
Even numbers in the array : NumberRepresenting Time
So for example in the array :
index : value
0 : 9
1 : 1
2 : 10
3 : 1
Would mean 9 + 10 on Day 1 (Monday).
The problem is, I have a an unpredictable number of these and I need to work out how many "sessions" there are per day. The rules of a session are that if they are on a different day they are automatically different sessions. If they are next to each other like in the example 9 + 10 that would count as a single session. The maximum number than can be directly next to eachother is 3. After this there needs to be a minimum of a 1 session break in between to count as a new session.
Unfortunately, we cannot also assume that the data will be sorted. It will always follow the even / odd pattern BUT could potentially not have sessions stored next to each other logically in the array.
I need to work out how many sessions there are.
My code so far is the following :
for($i = 0; $i < (count($TimesReq)-1); $i++){
$Done = false;
if($odd = $i % 2 )
{
//ODD WeekComp
if(($TimesReq[$i] != $TimesReq[$i + 2])&&($TimesReq[$i + 2] != $TimesReq[$i + 4])){
$WeeksNotSame = true;
}
}
else
{
//Even TimeComp
if(($TimesReq[$i] != ($TimesReq[$i + 2] - 1))&& ($TimesReq[$i + 2] != ($TimesReq[$i + 4] - 1)))
$TimesNotSame = true;
}
if($TimesNotSame == true && $Done == false){
$HowMany++;
$Done = true;
}
if($WeeksNotSame == true && $Done == false){
$HowMany++;
$Done = true;
}
$TimesNotSame = false;
$WeeksNotSame = false;
}
However this isn't working perfectly. for example it does not work if you have a single session and then a break and then a double session. It is counting this as one session.
This is, probably as you guessed, a coursework problem, but this is not a question out of a textbook, it is part of a timetabling system I am implementing and is required to get it working. So please don't think i'm just copy and pasting my homework to you guys!
Thank you so much!
New Code being used :
if (count($TimesReq) % 2 !== 0) {
//throw new InvalidArgumentException();
}
for ($i = 0; $i < count($TimesReq); $i += 2) {
$time = $TimesReq[$i];
$week = $TimesReq[$i + 1];
if (!isset($TimesReq[$i - 2])) {
// First element has to be a new session
$sessions += 1;
$StartTime[] = $TimesReq[$i];
$Days[] = $TimesReq[$i + 1];
continue;
}
$lastTime = $TimesReq[$i - 2];
$lastWeek = $TimesReq[$i - 1];
$sameWeek = ($week === $lastWeek);
$adjacentTime = ($time - $lastTime === 1);
if (!$sameWeek || ($sameWeek && !$adjacentTime)) {
if(!$sameWeek){//Time
$Days[] = $TimesReq[$i + 1];
$StartTime[] = $TimesReq[$i];
$looking = true;
}
if($sameWeek && !$adjacentTime){
}
if($looking && !$adjacentTime){
$EndTime[] = $TimesReq[$i];
$looking = false;
}
//Week
$sessions += 1;
}
}
If you want a single total number of sessions represented in the data, where each session is separated by a space (either a non-contiguous time, or a separate day). I think this function will get you your result:
function countSessions($data)
{
if (count($data) % 2 !== 0) throw new InvalidArgumentException();
$sessions = 0;
for ($i = 0; $i < count($data); $i += 2) {
$time = $data[$i];
$week = $data[$i + 1];
if (!isset($data[$i - 2])) {
// First element has to be a new session
$sessions += 1;
continue;
}
$lastTime = $data[$i - 2];
$lastWeek = $data[$i - 1];
$sameWeek = ($week === $lastWeek);
$adjacentTime = ($time - $lastTime === 1);
if (!$sameWeek || ($sameWeek && !$adjacentTime)) {
$sessions += 1;
}
}
return $sessions;
}
$totalSessions = countSessions(array(
9, 1,
10, 1,
));
This of course assumes the data is sorted. If it is not, you will need to sort it first. Here is an alternate implementation that includes support for unsorted data.
function countSessions($data)
{
if (count($data) % 2 !== 0) throw new InvalidArgumentException();
$slots = array();
foreach ($data as $i => $value) {
if ($i % 2 === 0) $slots[$i / 2]['time'] = $value;
else $slots[$i / 2]['week'] = $value;
}
usort($slots, function($a, $b) {
if ($a['week'] == $b['week']) {
if ($a['time'] == $b['time']) return 0;
return ($a['time'] < $b['time']) ? -1 : 1;
} else {
return ($a['week'] < $b['week']) ? -1 : 1;
}
});
$sessions = 0;
for ($i = 0; $i < count($slots); $i++) {
if (!isset($slots[$i - 1])) { // First element has to be a new session
$sessions += 1;
continue;
}
$sameWeek = ($slots[$i - 1]['week'] === $slots[$i]['week']);
$adjacentTime = ($slots[$i]['time'] - $slots[$i - 1]['time'] === 1);
if (!$sameWeek || ($sameWeek && !$adjacentTime)) {
$sessions += 1;
}
}
return $sessions;
}
Here is my little attempt at solving your problem. Hopefully I understand what you want:
$TimesReq = array(9,4,11,4,13,4,8,4,7,2,12,4,16,4,18,4,20,4,17,4);
// First just create weeks with all times lumped together
$weeks = array();
for($tri=0; $tri<count($TimesReq); $tri+=2){
$time = $TimesReq[$tri];
$week = $TimesReq[$tri+1];
$match_found = false;
foreach($weeks as $wi=>&$w){
if($wi==$week){
$w[0] = array_merge($w[0], array($time));
$match_found = true;
break;
}
}
if(!$match_found) $weeks[$week][] = array($time);
}
// Now order the times in the sessions in the weeks
foreach($weeks as &$w){
foreach($w as &$s) sort($s);
}
// Now break up sessions by gaps/breaks
$breaking = true;
while($breaking){
$breaking = false;
foreach($weeks as &$w){
foreach($w as &$s){
foreach($s as $ti=>&$t){
if($ti>0 && $t!=$s[$ti-1]+1){
// A break was found
$new_times = array_splice($s, $ti);
$s = array_splice($s, 0, $ti);
$w[] = $new_times;
$breaking = true;
break;
}
}
}
}
}
//print_r($weeks);
foreach($weeks as $wi=>&$w){
echo 'Week '.$wi.' has '.count($w)." session(s):\n";
foreach($w as $si=>&$s)
{
echo "\tSession ".($si+1).":\n";
echo "\t\tStart Time: ".$s[0]."\n";
echo "\t\tEnd Time: ".((int)($s[count($s)-1])+1)."\n";
}
}
Given $TimesReq = array(9,4,11,4,13,4,8,4,7,2,12,4,16,4,18,4,20,4,17,4); the code will produce as output:
Week 4 has 4 session(s):
Session 1:
Start Time: 8
End Time: 10
Session 2:
Start Time: 11
End Time: 14
Session 3:
Start Time: 16
End Time: 19
Session 4:
Start Time: 20
End Time: 21
Week 2 has 1 session(s):
Session 1:
Start Time: 7
End Time: 8
Hope that helps.

Categories