I am trying to build a function which calculates ticket sla based on working hours and skip calculations for non working hours and weekends and it shifts time accordingly to next day or to next working day. My response sla to a ticket is 30 minutes and if ticket insert date is within weekdays {Mon-Fri} and within business hours {08:00:00 – 17:00:00}, then my end date should be calculated based on following factors:
- for Monday to Thursday, time should shift to next 30 minutes in working hours in case insertDate falls within working hours, e.g. if case1: insertDate = ‘2020-07-16 16:00:00′; here, I am getting expected result, endDate =’2020-07-16 16:30:00’; and if insertDate timestamp exceeds the working hours window e.g. if case2: insertDate = ‘2020-07-16 16:50:00′; here, I am not getting expected result, which should be endDate =’2020-07-17 08:20:00’;
- for Weekends(Sat to Sun), any ticket created in this weekend window, the calculations should start from Mon and from 08:00:00 hours case3: insertDate = ‘2020-07-18 16:50:00′; here, I am not getting expected result, which should be endDate =’2020-07-20 08:30:00’;
Below is my code, which works for case1 fine, ubt breaks for case2 and case3, any help on this is highly appreciated.
<?php function calculateSLA($totalMinutes){ $insertDate = '2020-07-16 16:00:00'; $endDate = date('Y-m-d H:00:00',strtotime($insertDate)); //$t_min = date('i',strtotime($insertDate)); $BusinessStart = '08:00:00'; $BusinessEnd = '17:00:00'; $i = 1; $flag = false; while ($totalMinutes > 0) { $day = date('D', strtotime($endDate)); // fetching day of week if ($day == 'Sat') { // checking if saturday thenskip by adding 2 day to end date $endDate = date('Y-m-d', strtotime($endDate . " +2 Day")) . ' ' . $BusinessStart; // adding 2 day if saturday continue; } $diff = strtotime($BusinessEnd) - strtotime(date("H:i:s", strtotime($insertDate))); // getting difference of time of office end date and result end date var_dump($diff); $mins = $diff / (60); // difference in mins. if ($mins > $totalMinutes) { $mins = $totalMinutes; $flag = true; } else { $mins = $totalMinutes - $mins; // substracting mins from total minutes left } $endDate = date('Y-m-d H:i:s', strtotime("+$mins Minute", strtotime($insertDate))); // adding subtracted minutes if (!$flag) { $endDate = date('Y-m-d', strtotime($insertDate . " +1 Day")) . ' ' . $BusinessStart; // if not last loop add day to result end date } else { break; } } echo $endDate; } calculateSLA(30); ?>
Advertisement
Answer
I will post my version of the function. You pass the DateTime of ticket submission and get the DateTime of the allowed response.
function calculateSLA(DateTime $reportDate): DateTime { $responseDate = (clone $reportDate); // check conditions and add 1 minute to provided date 30 times (so 30 minutes) for($i=0; $i<30;$i++) { // if time is before 8:00 (working hours) skip to 8:00 if ($responseDate->format('G') < 8) { $responseDate->setTime(8, 0); } // if time is after 17:00 (working hours) skip to next day at 8:00 if ($responseDate->format('G') >= 17) { $responseDate->add(new DateInterval('PT15H')); $responseDate->setTime(8, 0); } // if at any time it is weekend skip to monday at 8:00 if (in_array($responseDate->format('D'), ['Sat', 'Sun'])) { $responseDate = $responseDate->modify('next monday 8:00'); } $responseDate->add(new DateInterval('PT1M')); } return $responseDate; }
And the code i used to test this function with different conditions:
function test(string $date, string $expected) { $result = calculateSLA(new DateTime($date)); echo 'date: '.$date.', expected: '.$expected.', got: '.$result->format('Y-m-d H:i:s').' '.($result->format('Y-m-d H:i:s') === $expected ? 'OK' : 'ERRROR').PHP_EOL; } test('2020-07-16 16:00:00', '2020-07-16 16:30:00'); // weekday during hours test('2020-07-16 16:50:00', '2020-07-17 08:20:00'); // weekday during hours until next day test('2020-07-18 16:50:00', '2020-07-20 08:30:00'); // weekend test('2020-07-16 06:50:00', '2020-07-16 08:30:00'); // weekday before working hours test('2020-07-16 20:50:00', '2020-07-17 08:30:00'); // weekday after working hours test('2020-07-17 16:50:00', '2020-07-20 08:20:00'); // friday during working hours until monday test('2020-07-17 17:50:00', '2020-07-20 08:30:00'); // friday after hours
The output:
date: 2020-07-16 16:00:00, expected: 2020-07-16 16:30:00, got: 2020-07-16 16:30:00 OK date: 2020-07-16 16:50:00, expected: 2020-07-17 08:20:00, got: 2020-07-17 08:20:00 OK date: 2020-07-18 16:50:00, expected: 2020-07-20 08:30:00, got: 2020-07-20 08:30:00 OK date: 2020-07-16 06:50:00, expected: 2020-07-16 08:30:00, got: 2020-07-16 08:30:00 OK date: 2020-07-16 20:50:00, expected: 2020-07-17 08:30:00, got: 2020-07-17 08:30:00 OK date: 2020-07-17 16:50:00, expected: 2020-07-20 08:20:00, got: 2020-07-20 08:20:00 OK date: 2020-07-17 17:50:00, expected: 2020-07-20 08:30:00, got: 2020-07-20 08:30:00 OK
Tricky part was friday that You didnt really mention, but I added test cases for it.