I need to figure out how much of an employee's shift is during the "night shift".
So, a night shift is any time from: 18:00 PM until 04:00 AM
My punches have a start and stop DateTime object. So if an employee has the following shift: 01:00 AM to 07:00 AM
They have 3 hours of that during the night shift. I calculate it in minutes because obviously that is more precise than hours.
However, my problem becomes if a shift carries over to midnight.
So they start at 22:00 PM on one date and finish next day at 07:00 AM.
I just cannot, for the life of me, figure out how to handle this.. Any help in this regard is much appriciated! Thanks all
EDIT Let me simplify my question as much as i can...
I have 2 DateTime objects representing a shift start and stop... Our company pays extra for any work done during the "night" which is between 18:00 PM and 04:00 AM... I need to calculate, how much (if any) of my shift is in that interval, so i can adjust the pay.
Here is my current code. I think it works for most cases i can think of, but i feel it is very complicated and convoluted.. maybe this is the right way, but i feel i made it more complicated than it can be.
private function calculateNightShift(\DateTime $shiftStart, \DateTime $shiftEnd)
{
// We know night-shift is always from 18:00 to 04:00
// So we just start with the interval on our shift-start
$nightStart = new \DateTime($shiftStart->format('Y-m-d') . '18:00:00');
$nightEnd = new \DateTime($shiftStart->format('Y-m-d') . '04:00:00');
$nightEnd->modify('+1 days'); // always next day comparing to the start, since we cross midnight
// The above contains our first possible night-shift interval that goes from shift_start date 18:00 to 04:00 next day
// We check for overlap here, and we also check for an overlap by moving the night shift 1 day in the past.
// This adjusts for any shift that crosses midnight
// First figure out if this shift is a night shift at all - if it is not, we return 0
// ($shiftStart >= $nightStart && $shiftStart <= $nightEnd) || ($shiftStart >= $nightStart->modify('-1 days') && $shiftStart <= $nightEnd->modify('-1 days'))
if ( (max($shiftStart, $nightStart) <= min($shiftEnd, $nightEnd)) || (max($shiftStart, $nightStart->modify('-1 days')) <= min($shiftEnd, $nightEnd->modify('-1 days'))) ) {
// First take all possible values into array (night start/end and shift start/end)
$nightShiftArray = [
$shiftStart,
$shiftEnd,
$nightStart,
$nightEnd
];
// Sort them
sort($nightShiftArray);
// Now the overlap is the value at index 1 and 2 (middle 2 values)
$overlapStart = $nightShiftArray[1];
$overlapEnd = $nightShiftArray[2];
$overlapDiff = $overlapStart->diff($overlapEnd);
// overlapDiff now contains the night shift total - store as minutes total
return ($overlapDiff->h * 60) + $overlapDiff->i;
} else {
return 0;
}
}