Page 1 of 1

Create a function to add hours onto a deadline

Posted: Thu Jun 26, 2014 5:18 am
by recci
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 is completely fails.

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

Code: Select all

$deadline_c = $this->add_deadline(64);

function add_deadline($hours){
    $UTC = new DateTimeZone("UTC");
    $now = new DateTime(); //current date/time
    $today = new DateTime($now->format('Y-m-d'));//get today's date only
    $deadline = $now->add(new DateInterval("PT{$hours}H"));//add on hours from database

    //set working hours
    $workingday = new DateTime();
    $working_daystart = $workingday->setTime(8, 30);
    $working_dayend = $workingday->setTime(17, 30);

    //check if deadline is after 17:30
    if($deadline > $working_dayend){
        $interval = $deadline->diff($working_dayend);
        //time over the working day in hours and minutes
        $over = $interval->format("%H:%I");
        //split time
        $over = explode(':', $over);
        //set to next working since deadline is after 17;30
        $nextday = $today->modify('+ 1 day');
        $nextday->setTime(8, 30);
        //Set deadline to the next day and add on hours and mins
        $deadline = $nextday->add(new DateInterval("PT".$over[0]."H"));
        $deadline = $deadline->add(new DateInterval("PT".$over[1]."M"));
    }
    //get days to add on if the next day is a weekend day
    $ifweekend = $this->check_day($deadline);
    $deadline = $deadline->modify($ifweekend);

    $deadline->setTimezone($UTC);//adjust to UTC
    $new_time = $deadline->format('Y-m-d H:i');

    return $new_time;

}

//checks if passed in date falls on a weekend day and if so passes back day difference
function check_day($deadline) {

    $day = $deadline->format(l);

    if($day == 'Saturday'){

        return '+ 2 days';
    }
    elseif($deadline == 'Sunday'){
        return "+ 1 days";
    }
    else {
        return '+ 0 days';
    }
}


Re: Create a function to add hours onto a deadline

Posted: Thu Jun 26, 2014 6:03 am
by recci
Ok I have updated my function to this but it is still not working correclty:

this is returning back 2014-06-29 17:41:00 which is a sunday but sunday is not a working day.

$future = addRollover('2014-06-26 11:41:00', '+63 hours');
echo $future->format('Y-m-d H:i:s');

Code: Select all

<?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

Re: Create a function to add hours onto a deadline

Posted: Thu Jun 26, 2014 6:08 am
by Celauran
Looks like your business days are from 08:30 through 17:30 and, save for priority 1, you're working in increments of 9 hours. Might be easier to change '+63 hours' to '+7 days' etc.

Re: Create a function to add hours onto a deadline

Posted: Thu Jun 26, 2014 6:56 am
by recci
The hours are stored in the database as an hours number so cant really do that. I also dont quite understand what your getting at.

Re: Create a function to add hours onto a deadline

Posted: Thu Jun 26, 2014 8:36 am
by Celauran
recci wrote:I also dont quite understand what your getting at.
You don't see how 63 hours is seven 9-hour days?

Re: Create a function to add hours onto a deadline

Posted: Thu Jun 26, 2014 9:01 am
by recci
7x9 =63 bro but this isnt really helping. Just assume it has to be done in hours, using DateTime this should make no difference weather its hours or days anyway.

Re: Create a function to add hours onto a deadline

Posted: Thu Jun 26, 2014 9:05 am
by Celauran
My point is that if you're adding 9 hours, checking if that extends past closing time and, if so, adding a day and adding the remaining hours after the next day's opening will give you the exact same result as just adding 1 day, but your way is significantly more complex. :shrug:

Re: Create a function to add hours onto a deadline

Posted: Thu Jun 26, 2014 9:32 am
by recci
I see your point but potentially any amout of hours could be used as the user has the ability to alter the priorities to anything they like.

Re: Create a function to add hours onto a deadline

Posted: Mon Jun 30, 2014 3:57 am
by recci
Ended up with this:

Code: Select all

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>';