Matching user time logs to day shift in an attendance system - php

I'm trying to create a simple attendance application with Laravel. I'm just a little stuck with the logic side.
What I'm trying to do is to match up the time logs of users to the correct schedule.
So in our office, we could have from 2 to 3 breaks, so a typical work shift will look like this:
Time In - 06:00 AM
Break Out 1 - 07:15 AM
Break In 1 - 07:30 AM
Break Out 2 - 11:30 AM
Break In 2 - 12:00 PM
Time Out - 03:00 PM
Now a user typically just uses the biometric device and selects "in" or "out".
My problem is given something like this:
05:58 AM, in
07:17 AM, out
07:31 AM, in
05:58 AM, out
How can the system tell which time log (07:17 AM) belongs to which time slot (Break Out 1)?
Thank you so much for the help, and if my question is unclear, I'm sorry.
Here's a sample code of what I've done so far. It works but I think it's really messy:
$day_shift = [
"time_in" => date('H:i:s', strtotime("06:00 AM")),
"break_out_1" => date('H:i:s', strtotime("07:15 AM")),
"break_in_1" => date('H:i:s', strtotime("07:30 AM")),
"break_out_2" => date('H:i:s', strtotime("11:30 AM")),
"break_in_2" => date('H:i:s', strtotime("12:00 PM")),
"break_out_3" => '',
"break_in_3" => '',
"time_out" => date('H:i:s', strtotime("03:00 pM")),
];
foreach ($day_shift as $key => $userScheduleTime) {
if ($userScheduleTime !== "") {
$time = $logDate->date." ".$userScheduleTime;
} else {
$time = "";
}
$schedules[] = array('time' => $time, 'type' => $types[$i%2],'name'=>$key);
$i++;
}
// logTimes is a collection of time logs
foreach ($logTimes as $logTime) {
$logs[] = $logTime->toArray();
}
$cloneLogs = $logs;
$lastlog = end($cloneLogs);
if ($lastlog["log_type"] == "login") {
$dayOut = "";
} else {
$dayOut = $lastlog["log_time"];
}
$lastout = null;
$size = count($logs);
do {
if ($logs[$size-1]['log_type'] == 'logout') {
$lastout = $logs[$size-1];
break;
}
$size--;
} while ($size > 0);
$lastlog = null;
for ($i = 0; $i < count($schedules); $i++) {
$logTime = current($logs);
if ($lastlog == $logTime['log_type']) {
next($logs);
}
// checks the first log, calculates how late the person is
if ($i == 0) {
if ($logTime['log_type'] == "login") {
$timein = $schedules[0]['time'];
if (strtotime(date("Y-m-d H:i", strtotime($logTime['log_time']))) >
strtotime(date("Y-m-d H:i", strtotime($timein)))) {
$lates[$logTime['log_time']] = true;
$lates["totallate"] += getDifferenceInMinutes($logTime['log_time'], $timein);
}
$lastlog = $logTime["log_type"];
next($logs);
}
}
if ($schedules[$i]['type']==$logTime['log_type'] && $i!=0 && $lastlog !== $logTime["log_type"]) {
$nextSched = isset($schedules[$i+1])?$schedules[$i+1]:$schedules[$i];
$j = 1;
while ($nextSched['time']=="" && ($i+$j)<=count($schedules)) {
$nextSched = $schedules[$i+$j];
$j++;
}
if (strtotime($nextSched['time'])>strtotime($logTime['log_time']) && $logTime["log_time"] != $dayOut) {
// checks and calculates if the user has undertime
if (strtotime($nextSched['time']) > strtotime($logTime['log_time']) && $nextSched['type']=='login') {
if (strtotime($logTime['log_time']) < strtotime($schedules[$i]['time'])) {
$lates[$logTime['log_time']] = true;
$lates["totalunder"] += getDifferenceInMinutes($logTime['log_time'], $schedules[$i]['time']);
}
}
// checks and calculates if the user has overbreaks
if (date('H:i', strtotime($schedules[$i]['time'])) <
date('H:i', strtotime($logTime['log_time'])) &&
$logTime['log_type'] == 'login') {
$lates[$logTime['log_time']] = true;
$lates["totalover"] += getDifferenceInMinutes($schedules[$i]['time'], $logTime['log_time']);
}
$lastlog = $logTime["log_type"];
next($logs);
}
if ($i+1==count($schedules)) {
next($logs);
}
if ($logTime["log_time"] == $dayOut && $dayOut !== null) {
$timeOut = $schedules[count($schedules)-1]["time"];
if (strtotime(date("Y-m-d H:i", strtotime($logTime["log_time"]))) <
strtotime(date("Y-m-d H:i", strtotime($timeOut)))) {
$lates[$logTime["log_time"]] = true;
$lates["totalunder"] += getDifferenceInMinutes($logTime['log_time'], $timeOut);
$lastlog = $logTime["log_type"];
}
break;
}
}
}

Related

Find records between two time slots in 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
}
}
}

i want to sum all digit in a number

i want to add all digit in a number and if it is 11,22 then i want to display only 11 or 22 else i want to make it a single digit.
example 30=3+0=3
28=2+8=10=1+0=1
i just made a codebut it have an error
please help.
<?php
$day = 17;
$month = 8;
$year = 1993;
function sumday($day)
{
if ($day == 11)
{
$sday = 11;
}
elseif ($day == 22)
{
$sday = 22;
}
elseif ($day == 29)
{
$sday = 11;
}
else
{
do {
$nday = $day . "";
$sday = 0;
for ($i = 0; $i < strlen($nday); ++$i)
{
$sday += $nday[$i];
}
while ($sday <=9);
}
return $sday;
}
First of all I would suggest you to learn to separate the tasks that a function do.
You ask to sum up the digits of a number, you may first create a function called sum_digits
<?php
function sum_digits($num) {
if ($num < 10)
return $num;
return $num % 10 + sum_digits(floor($num/10));
}
and then via conditional do whatever you need to do.
please refer to unnikked's answer, that's a good answer.
And here's the full code, combined with unnikked's answer
<?php
$day = 17;
$month = 8;
$year = 1993;
function sumday($day)
{
if ($day == 11)
{
$sday = 11;
}
elseif ($day == 22)
{
$sday = 22;
}
elseif ($day == 29)
{
$sday = 11;
}
else{
$sday = $day;
do {
$sday = $sday % 10 + floor($sday/10);
} while ($sday >= 10);
}
return $sday;
}
?>
EDIT: If you want to return the sum if it's 11,22,33 in the while loop, then put the conditions in the while loop rather than using if else condition, it's much simpler tho :)
function sumday($day)
{
$sday = $day;
while ($sday >= 10 && $sday != 11 && $sday != 22 && $sday != 29){
$sday = $sday % 10 + floor($sday/10);
}
return $sday;
}
EDIT: here's the logic that can split the day and sum them
function sumday($day)
{
$sday = $day;
$arrday = str_split($sday); // split the day into array
$sumarrday = 0;
for($i = 0; $i < strlen((string)$sday); $i++){
$sumarrday = $sumarrday + $arrday[$i]; // sum the day from the array
}
$sday = $sumarrday;
// here you can modify the condition of while statement for your needs
// for example, if you want to return 29 when 29 shows up, add this to your condition, && $sday != 29
while ($sday >= 10){
$sday = $sday % 10 + floor($sday/10);
}
return $sday;
}
Try this:
else {
$nday = $day . ""; //moved out wrom loop
do {
$sday = 0;
for ($i = 0; $i < strlen($nday); ++$i)
{
$sday += $nday[$i];
}
$nday = $sday . ""; // you forget this line
while ($sday <=9);
}

Sick Day Entitlement based on years of service with a company

got an update for you with my function. This also now works as it should, but I need it to work out total sick, based on years of service up to the 1st day they take of sick. Hope I have made that clear. I have marked the line of code that works out my sick but i only gives me one all the time, even when I know where are more years for that selected user.
Please help?
Glenn Curtis
function sickDay($id = null) {
if($this->CURRENT_USER['User']['role_id'] > 3) { //directors and admins
/*if(empty($this->data) || !isset($this->data['Holiday']['id'])) {
} else {*/
//Get the user sick days
$userSickDays = $this->Holiday->find(
'all',
array(
'conditions' => array(
'Holiday.holidaystype_id' => 3,
'Holiday.user_id' => $id
),
'order' => 'Holiday.startson ASC'
));
//Get years of service
$userContracts = $this->Holiday->User->Contract->find(
'all',
array(
'conditions' => array( 'Contract.user_id' => $id), //$data['user_id']),
'order' => array( 'Contract.startson' => 'ASC' )
));
//Loop through the user's sick days
foreach ($userSickDays as $k => $sickDay) {
//Get number of days in the current sick day
$totSickdays = $this->Holiday->getNumberDaysFromHoliday($sickDay['Holiday']['id']);
//Get number of sick days for the past 12 months
if($k > 0) {
for($i=0; $i<$k; $i++) {
if((strtotime(gmdate("Y-m-d", $sickDay['Holiday']['startson'])." -1 year GMT")) <= $userSickDays[$i]['Holiday']['startson']) {
$totSickdays += $this->Holiday->getNumberDaysFromHoliday($userSickDays[$i]['Holiday']['id']);
}
}
}
foreach ($userContracts as $y => $contract) {
THIS LINE HERE->$yearsService = $contract['Contract']['startson'] <= $sickDay['Holiday']['startson'];
if ($contract['Contract']['startson'] <= $sickDay['Holiday']['startson']) {
if ($yearsService <= 1) {
$entitlement = 10;
$remaingDays = $entitlement - $totSickdays;
//echo 'one year';
} elseif ($yearsService <= 2) {
$entitlement = 20;
$remaingDays = $entitlement - $totSickdays;
//echo 'two years';
} elseif ($yearsService <= 4) {
$entitlement = 40;
$remaingDays = $entitlement - $totSickdays;
//echo 'up to five years';
} elseif ($yearsService >= 5) {
$entitlement = 60;
$remaingDays = $entitlement - $totSickdays;
//echo 'five years or more';
} else {
$entitlement = 0;
$remaingDays = 0;
//echo 'no sick pay';
}
} //End of if statement.
} //End of $userContracts Foreach Loop
debug($yearsService);
} //End of Foreach Loop
//$this->render('/artists/holidayslist');
//} //End For if empty check
} // End for if CURRENT_USER
die();
} //End of Function
OLD POST BELOW
Now I have asked for help on this before, however that was over one selected area of my function, to get number of sick days. That now works, I found a function that was built for me within the site I am working on. So I have total number of sick days entered within the database. Now I don't seem to be able to work out why I cant set that to my years of service.
To make my myself more clearly, the outcome of this function is to check the current users sick taken within a selected year. But to a annual year, a contracted year, e.g. may to may.
That is why I have a number of if statements to set up the users entitlement, as that changed based on years of service. Then when that is set, to take off the sick days the user has taken within that contracted year.
I hope I have explain what I want to do, if that is not clear, please let me know and I try and explain in more detail.
Please help, this is written for a page used in a CakePHP project.
Many Many Thanks
Glenn Curtis
function sickDay($id = null) {
if($this->CURRENT_USER['User']['role_id'] > 3) { //directors and admins
//Caculate if it's a full pay, half pay or nothing
//$data = $this->data['Holiday'];
//Get Holidaytypes
$userSickDays = $this->Holiday->find(
'all',
array(
'conditions' => array(
'Holiday.holidaystype_id' => 3,
'Holiday.user_id' => $id
)
)
);
//Get starting date
$contracts = $this->Holiday->User->Contract->find(
'all',
array(
'conditions' => array(
'Contract.user_id' => $id //$data['user_id']
),
'order' => array(
'Contract.startson' => 'ASC'
)
)
);
$start = array_shift($contracts);
$end = array_pop($contracts);
$endDate = $end['Contract']['endson'];
$startDate = $start['Contract']['startson'];
if (empty($endDate)) { $endDate = time('now'); }
$SortEnd = strftime("%Y", $endDate);
$SortStart = strftime("%Y", $startDate);
$YearsService = $SortEnd - $SortStart;
//Get How Many sick days
foreach ($userSickDays as $sickDay) {
$typesDataEnds = strtotime($sickDay['Holiday']['endson']);
$typesDataStarts = $sickDay['Holiday']['startson'];
$DateNow = date('U', strtotime('Now'));
$GetSickDays = $this->Holiday->getNumberDaysFromHoliday($sickDay['Holiday']['id']);
$TotalSick += $GetSickDays;
if ($YearsService <= 1) {
$SetFullEntitlement = 5;
$SetHalfEntitlement = 5;
//echo 'one year';
} elseif ($YearsService <= 2) {
$SetFullEntitlement = 10;
$SetHalfEntitlement = 10;
//echo 'two years';
} elseif ($YearsService <= 5) {
$SetFullEntitlement = 20;
$SetHalfEntitlement = 20;
//echo 'up to five years';
} elseif ($YearsService >= 6) {
$SetFullEntitlement = 30;
$SetHalfEntitlement = 30;
//echo 'five years or more';
} else {
$SetFullEntitlement = 0;
$SetHalfEntitlement = 0;
//echo 'no sick pay';
}
}
//$this->render('/artists/holidayslist');
} // End for if CURRENT_USER
die();
} //End of Function
your code seems too complicated for what (it seems) is just
return (($TotalAnnualEntitlement - $SickDaysTakenThisYear) > 0) ? true : false;
You need to work out their entitlement, based on how long they have been contracted - easy enough, You then need to take their entitled holiday from the number of days they have already taken. Again, seems easy enough.
If they have any days remaining, you want to return true. If there have used their allowance, or gone over, return false.
or am i missing something?

For loop Logic Problems with PHP

This is my new code, its almost working, but I think my while loop is wrong some where?
Same as before, gets users taken sick puts it into a var. Then get users entitlement based on years of service, then work out what they have taken and see if the user has used all the full entitlement, then to see if they have used all there half pay entitlement.
Please Help?
if($this->CURRENT_USER['User']['role_id'] > 3) { //locks out user types
//Get Holidaytypes
$types = $this->Holiday->find(
'all',
array(
'conditions' => array(
'Holiday.holidaystype_id' => 3,
'Holiday.user_id' => $id
)));
//Get starting date
$contracts = $this->Holiday->User->Contract->find(
'all',
array(
'conditions' => array(
'Contract.user_id' => $id//$data['user_id']),
'order' => array('Contract.startson' => 'ASC')
)
);
//Get How Many sick days
foreach ($types as $key => $value) {
global $SickTotal;
$typesDataEnds = strftime ("%u-%d-%Y", $types[$key]['Holiday']['endson']);
$typesDataStarts = strftime ("%u-%d-%Y", $types[$key]['Holiday']['startson']);
$SickTotal = count($typesDataEnds - $typesDataStarts);
//echo $SickTotal;
//Get Contract Start & End Dates
$start = array_shift($contracts);
$end = array_pop($contracts);
$endDate = $end['Contract']['endson'];
$startDate = $start['Contract']['startson'];
if (empty($endDate)) {
$endDate = time('now');
}
if (!empty($startDate)) {
$SortEnd = strftime("%Y", $endDate);
$SortStart = strftime("%Y", $startDate);
$YearsService = $SortEnd - $SortStart;
if ($YearsService <= 1) {
$SetFullEntitlement = 5;
$SetHalfEntitlement = 5;
//echo 'one year';
} elseif ($YearsService >= 2) {
$SetFullEntitlement = 10;
$SetHalfEntitlement = 10;
//echo 'two years';
} elseif ($YearsService >= 5) {
$SetFullEntitlement = 20;
$SetHalfEntitlement = 20;
//echo 'up to five years';
} elseif ($YearsService > 5) {
$SetFullEntitlement = 30;
$SetHalfEntitlement = 30;
//echo 'five years or more';
} else {
$SetFullEntitlement = 0;
$SetHalfEntitlement = 0;
//echo 'no sick pay';
}
} else {
$YearsService = 0;
//echo 'Sorry No Start Date For You Found!';
}
while ($SickTotal > 0) {
if ($SetFullEntitlement != 0) {
$SetFullEntitlement--;
} elseif ($SetHalfEntitlement != 0) {
$SetHalfEntitlement--;
}
}
echo 'FullPay:';
echo $SetFullEntitlement;
echo '<br/><br/>Halpay:';
echo $SetHalfEntitlement;
echo $SickTotal;
}
debug($types);
die();
//$this->render('/artists/holidayslist');
}
}
If ($startdate <= 1 year) {
If that's literally what you've typed, it's not going to work. Maybe strtotime might make some sense of it?
In any case,
For ($i = $Totalsick, $i >= $Fulldays, $i--) {
For ($i = $Totalsick, $>= $Halfdays, $i--) {
you're missing an $i in there - you're evaluating nothing against $Halfdays. You're also using $i for two seperate loops, so they're both on the same counter. switch your second loop to use a different variable.
I'm not quite sure I follow exactly what you are trying to do here but you could tidy up your code a bit and save on lines of code. I assume that $startdate is how many years ago the user started.
$sickdays= array( 0=>5, 1=>10, 2=>20, 5=>30 );
$userdays= 0;
foreach ( array_keys( $sickdays ) as $years_service )
{
if ( $years_service <= $startdate )
$userdays=$sickdays[$years_service];
}
Now $userdays should be the correct number of paid sick days and half days ( the two are always the same in your example ) for this user. A simple comparison should be sufficient to check whether they have taken less or more than their allotted number of days and half days.
I haven't tried this as I'm not working with PHP today, so I'm sure someone will shoot me down directly, but by setting your variables once and writing fewer lines you should find your code gets easier to maintain.

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