Skip to content
Advertisement

calculating sla based on minutes on working hours and business days

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:

  1. 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’;
  2. 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.

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement