0

Basically I am trying to create a basic case logging system and when somebody opens a new case, the case is assigned a priority with a given number of hours. For example priority 1 is 4 hours, 2 is 9 hours, 3 is 36hours and 4 is 63 hours.

Now adding hours onto a time stamp is easy but the catch is I need to take into account working hours which are 08:30 to 17:30 Monday to Friday. So if a case is given a 4 hour priority and the deadline for this falls after 17:30 on a week day then the deadline is extended to the next working day. Basically the deadline is 4 working hours.

Example:

Case created on: 19/05/2014 16:55 - with Priority 1 (4 Hours) Deadline is now: 20/05/2014 11:55

Make sense?

Another catch is I need to take into account hours On Hold and these two have to be only within working hours. But ill worry about that later.

I am trying to use the modern DateTime class for this as far as possible.

Here is what I have so far, I am struggling with the logic. It works if the deadline is within a day but if I add something like 63 hours it returns back on a Sunday.

Where am I going wrong here? Brain is fried with this :(

 <?php
function addRollover($givenDate, $addtime) {
$datetime = new DateTime($givenDate);
$datetime->modify($addtime);

if (in_array($datetime->format('l'), array('Sunday','Saturday')) || 
    17 < $datetime->format('G') || 
    (17 === $datetime->format('G') && 30 < $datetime->format('G'))
) {
    $endofday = clone $datetime;
    $endofday->setTime(17,30);
    $interval = $endofday->diff($datetime);

    $datetime->add(new DateInterval('P1D'));
    if (in_array($datetime->format('l'), array('Saturday', 'Sunday'))) {
        $datetime->modify('next Monday');
    }
    $datetime->setTime(8,30);
    $datetime->add($interval);
}

  return $datetime;
}
//this is returning back 2014-06-29 17:41:00 which is a sunday.
$future = addRollover('2014-06-26 11:41:00', '+63 hours');
echo $future->format('Y-m-d H:i:s');

See it in action: http://3v4l.org/Ac8ro

Here's an explanation of what's supposed to be going on in the function:

First we create a DateTime object representing our starting date/time

We then add the specified amount of time to it (see Supported Date and Time Formats)

We check to see if it is a weekend, after 6PM, or in the 5PM hour with more than 30 minutes passed (e.g. after 5:30PM)

If so we clone our datetime object and set it to 5:30PM

We then get the difference between the end time (5:30PM) and the modified time as a DateInterval object

We then progress to the next day

If the next day is a Saturday we progress to the next day

If the next day is a Sunday we progress to the next day

We then set our time to 8:30AM

We then add our difference between the end time (5:30PM) and the modified time to our datetime object

We return the object from the function

user794846
  • 1,881
  • 5
  • 29
  • 72

1 Answers1

0

UPDATE 2

Updated the code as per based on suggestions provided

<?php
function addRollover($givenDate, $addtime, $dayStart, $dayEnd, $weekDaysOnly) {
    //Break the working day start and end times into hours, minuets
    $dayStart = explode(',', $dayStart);
    $dayEnd = explode(',', $dayEnd);
    //Create required datetime objects and hours interval
    $datetime = new DateTime($givenDate);
    $endofday = clone $datetime;
    $endofday->setTime($dayEnd[0], $dayEnd[1]); //set end of working day time
    $interval = 'PT'.$addtime.'H';
    //Add hours onto initial given date
    $datetime->add(new DateInterval($interval));
    //if initial date + hours is after the end of working day
    if($datetime > $endofday)
    {
        //get the difference between the initial date + interval and the end of working day in seconds
        $seconds = $datetime->getTimestamp()- $endofday->getTimestamp();

        //Loop to next day
        while(true)
        {
            $endofday->add(new DateInterval('PT24H'));//Loop to next day by adding 24hrs
            $nextDay = $endofday->setTime($dayStart[0], $dayStart[1]);//Set day to working day start time
            //If the next day is on a weekend and the week day only param is true continue to add days
            if(in_array($nextDay->format('l'), array('Sunday','Saturday')) && $weekDaysOnly)
            {
                continue;
            }
            else //If not a weekend
            {
                $tmpDate = clone $nextDay;
                $tmpDate->setTime($dayEnd[0], $dayEnd[1]);//clone the next day and set time to working day end time
                $nextDay->add(new DateInterval('PT'.$seconds.'S')); //add the seconds onto the next day
                //if the next day time is later than the end of the working day continue loop
                if($nextDay > $tmpDate)
                {
                    $seconds = $nextDay->getTimestamp()-$tmpDate->getTimestamp();
                    $endofday = clone $tmpDate;
                    $endofday->setTime($dayStart[0], $dayStart[1]);
                }
                else //else return the new date.
                {
                    return $endofday;

                }
            }
        }
    }
    return $datetime;
}


$currentTime = '2014-06-27 08:30:00';
$dayStart = '8,30';
$dayEnd = '17,30';

$future = addRollover($currentTime, 65, $dayStart, $dayEnd, true);

echo "Results: </br>";
echo $future->format('Y-m-d H:i:s').'</br>';
Community
  • 1
  • 1
gpr
  • 485
  • 1
  • 5
  • 15
  • If I was to put in 2014-06-27 17:29:00 which is a Friday Id expect the output to be Monday: 2014-06-30 12:29:00 – user794846 Jun 26 '14 at 11:54
  • it does not not seem to work for me. If I put it right nows datetime and add 36 hours it returns 2014-06-27 17:30 not sometime on Tuesday – user794846 Jun 26 '14 at 13:12
  • Input '2014-06-26 08:30:00', 36 Output 2014-06-27 11:30:00 – user794846 Jun 26 '14 at 13:26
  • Also its always rounding up to the :30.00 it should be down to the exact minuet – user794846 Jun 26 '14 at 13:31
  • Never noticed you had updated!! This seems to working "ya Dancer!!" – user794846 Jun 27 '14 at 15:51
  • How would I add hours on hold into this function. If its put on hold the datetime is stored. When its taken off hold the time diff in hours between being put on hold and taken off is used but this also is within the working hours timeframe. – user794846 Jun 27 '14 at 15:59
  • In fact I probably don’t need onhold in the same function. I can use this function to create and store the initial deadline then if its placed on hold I pass the length of time it was on hold for in hours and the date it went on hold back to this function and just extend the deadline. – user794846 Jun 27 '14 at 16:27
  • It would be good if it could be made more flexible though, Such as passing in the working day start and end times as params and make skip weekends an optional. – user794846 Jun 27 '14 at 16:29
  • you can add a bool into the function and provide the support for optional weekends something like this. `if(in_array($endofday->format('l'), array('Sunday','Saturday')) && $weekDays)` and pass the $weekDays argument as shown `$future = addRollover($currentTime, $value,true);` if true it will perform a weekend check ,else it will ignore it. – gpr Jun 27 '14 at 19:25
  • Ok Iv updated your function to accept the working day start and end times as parms and added the optional weekend param. Iv also got rid of all the redundant variables and commented the code. Check over what iv done here: http://3v4l.org/eKZsE If you don’t seen anything wrong update your answer and Ill accept it as the definitive answer. – user794846 Jun 30 '14 at 00:11
  • Thanks for your help, Now I just need to work out how calculate hours difference in business hours. – user794846 Jun 30 '14 at 10:41