I have list of times for staff. I need to find out if any of the staff was working alone and how many minutes they were working alone for the day
| staff| start | end |
|:--- |:--- |:--- |
| 1 | 11:05 | 20:00 |
| 2 | 11:00 | 17:00 |
| 3 | 19:00 | 03:00 |
| 4 | 13:00 | 20:00 |
| 5 | 19:00 | 03:00 |
With Andreas' help, following is the code that gets the first and last person who was working alone with alone minutes, but its not quite right. Because if there were 3 people with different times that worked alone, it will give a problem. https://3v4l.org/6OmjO
$staff = array(1,2,3,4,5);
$start = array("11:05", "11:00", "19:00", "13:00", "19:00");
$end = array("20:00", "17:00", "03:00", "20:00", "03:05");
array_multisort($start, $end, $staff);
$aloneStart = (strtotime($start[1]) - strtotime($start[0])) / 60; // first and second items are the ones that may be working alone at start
$aloneEnd = (strtotime($end[count($end) - 1]) - strtotime($end[count($end) - 2])) / 60; // last and second to last are the ones that may be working alone at end
if ($aloneStart > 0)
{
$staffAloneStart = $staff[0]; //must be the first who worked alone
echo "minutes alone at start: " . $aloneStart . " and it was " . $staffAloneStart . "\n";
}
if ($aloneEnd > 0)
{
$staffAloneEnd = $staff[count($end) - 1]; // must be the last to end that worked alone
echo "minutes alone at end: " . $aloneEnd . " and it was " . $staffAloneEnd . "\n";
}
$aloneTime = intval($aloneStart) + intval($aloneEnd);
echo "total time alone " . $aloneTime;
with following array, you will see the minutes for first user needs to be more then 5 minutes, because he is working alone more at evening.
$staff = array(1, 2, 3, 4, 5);
$start = array("11:05", "11:10", "19:00", "13:00", "19:00");
$end = array("20:00", "17:00", "03:00", "16:00", "03:00");
Got it!
It took some time but I found a solution.
Managed to find a solution to mickmacks test case.
Here is a ten person case and it seems to hold up for that too.
And see the beauty run https://3v4l.org/bT2bZ
It took me a long time to figure out I needed a dummy. Who knew a dummy could be useful?
I am doing a complete re-write of my answer so that it is clear and flows in the proper order. I made a couple of minor refinements from my previous method, but nothing drastic.
First is the data preparation code. I convert the OP's
hh:mm
time in and out values to simple minute values, while maintaining employee ids as keys.This is the data processing snippet. I have built in a shortcut -- if one employee shares an identical shift with another employee, then the first employee is immediately deemed to have zero minutes alone (obviously). Otherwise, an employee's shift is compared one by one against the other employees' shifts to determine how many minutes they are alone.
Output:
To help you follow what is happening inside of
whittle()
660
to1260
. ($pieces_of_shift
is an array with just one subarray with two elements - start minutes and end minutes)$pieces_of_shift=[[660,1260]];
$pieces_of_shift
subarray is replaced by two new subarrays -- the alone time at the start of the shift, and the alone time at the end of the shift:660
to780
and900
to1260
.$pieces_of_shift=[[660,780],[900,1260]];
$pieces_of_shift=[[660,780],[900,1020],[1140,1260]];
660
to780
,900
to1020
, and1140
to1260
. These 3 ranges of alone time (2hrs each) yields 6 hours of total solo work or 360 minutes.Here is a demo with additional comments.
If there is a high probability or high volume of duplicate shifts in a particular batch, total iterations inside of
whittle()
can be reduced by writing$colleague_shifts=array_map('unserialize', array_unique(array_map('serialize', $shifts)))
before the firstforeach()
loop.For that matter, the same multi-functional approach could be used to shortcut several duplicate shifts before the call of
foreach($shifts...)
, but I have chosen not to implement that approach because it may not be worth the convolution.