2

How would I structure the conditions to add two hours only to dates between 08:30 in the morning until 18:30 of the evening, excluding Saturday and Sunday?

In the case that a time near the border (e.g. 17:30 on Tuesday) is given, the left over time should be added to the beginning of the next "valid" time period.

For example: if the given date was in 17:30 on Tuesday, the two hour addition would result in 9:30 on Wednesday (17:30 + 1 hour = 18:30, 8:30 + the remainder 1 hour = 9:30). Or if the given date was in 17:00 on Friday, the result would be 9:00 on Monday (17:00 Friday + 1.5 hours = 18:30, 8:30 Monday + the remainder .5 hours = 9:00)

I know how to simply add two hours, as follows:

$idate1 = strtotime($_POST['date']);
$time1 = date('Y-m-d G:i', strtotime('+120 minutes', $idate1));
$_POST['due_date']  = $time1;

But what would I add to accomplish the above?

cincodenada
  • 2,877
  • 25
  • 35
user1233875
  • 175
  • 4
  • 16

2 Answers2

1

Using "magic numbers" and doing a lot of math with dates makes your code less readable, and also can cause problems - it doesn't deal well with leapyears, daylight savings time, time zones, or all the other weirdness that comes with dates and time.

When possible, you should always use helper functions like strtotime() to deal with dates and avoid doing math directly.

Here's my shot at doing what you want, it's not perfect (you can't add a time period larger than the gap between two periods - that is, 14 hours from 18:30 to 8:30 - and it still uses some raw math, but it's an improvement:

<?php
    function addRollover($givenDate, $addtime) {
        $starttime = 8.5*60; //Start time in minutes (decimal hours * 60)
        $endtime = 18.5*60; //End time in minutes (decimal hours * 60)

        $givenDate = strtotime($givenDate);

        //Get just the day portion of the given time
        $givenDay = strtotime('today', $givenDate);
        //Calculate what the end of today's period is
        $maxToday = strtotime("+$endtime minutes", $givenDay);
        //Calculate the start of the next period
        $nextPeriod = strtotime("tomorrow", $givenDay); //Set it to the next day
        $nextPeriod = strtotime("+$starttime minutes", $nextPeriod);  //And add the starting time
        //If it's the weekend, bump it to Monday
        if(date("D", $nextPeriod) == "Sat") {
            $nextPeriod = strtotime("+2 days", $nextPeriod);
        }

        //Add the time period to the new day
        $newDate = strtotime("+$addtime", $givenDate);
        //print "$givenDate -> $newDate\n";
        //print "$maxToday\n";
        //Get the new hour as a decimal (adding minutes/60)
        $hourfrac = date('H',$newDate) + date('i',$newDate)/60;
        //print "$hourfrac\n";

        //Check if we're outside the range needed
        if($hourfrac < $starttime || $hourfrac > $endtime) {
            //We're outside the range, find the remainder and add it on
            $remainder = $newDate - $maxToday;
            //print "$remainder\n";
            $newDate = $nextPeriod + $remainder;
        }

        return $newDate;
    }
?>

I've commented out the print statements I had for debugging, you can uncomment them if you want to see how it works (which I recommend!) You use it as such:

<?php
    print date('Y-m-d H:i:s',addRollover('2013-01-01 17:30','2 hours')) . "\n";
    print date('Y-m-d H:i:s',addRollover('2013-01-01 18:00','3 hours')) . "\n";
    print date('Y-m-d H:i:s',addRollover('2013-01-04 17:00','150 minutes')) . "\n";
?>

Results in:

2013-01-02 09:30:00
2013-01-02 11:00:00
2013-01-07 09:30:00

This code should deal just fine with most weirdnesses of dates, such as timezones, daylight savings, and such. It would be even better implemented with PHP's DateTime class, but that is fairly new and I'm not as familiar with it, so I stuck with strtotime().

cincodenada
  • 2,877
  • 25
  • 35
  • tested and it works, this is exactly what i wanted, tnk you so much for your help – user1233875 Nov 26 '13 at 01:14
  • there is a problem with your function, when i use a date like ( 2013-11-26 12:30 ) he gives me ( 2013-11-27 04:30:00 ) – user1233875 Nov 26 '13 at 22:02
  • here you can find it as question : http://stackoverflow.com/questions/20229093/php-add-two-hours-to-a-date-within-given-hours-using-function – user1233875 Nov 26 '13 at 22:32
  • Sounds like it's time for some debugging. If you uncomment the `print` statements, maybe wrapping them in a date() function so they're more readable, can you find where things are going wrong? – cincodenada Nov 27 '13 at 00:46
0

The date function works with UNIX timestamps, therefore I just add 86400 (seconds in a day), then divide it by 24 and multiply by 2. That's exactly 2 hours more.

$time1 = date('Y-m-d G:i', strtotime($idate1)+86400/12);

If you'd like to only apply these changes in a certain period, you can use ( timestamp modulo 86400 ) formula to get the hours and minutes.

if(($idate%86400)>=(86400/24*8.5)&&($idate%86400)<=(86400/24*18.5)) 
$time1 = date('Y-m-d G:i', strtotime($idate1)+86400/12);

For filtering the weekends, date() will help you:

if(date("D",$idate)=="Sun" || date("D",$idate)=="Sat)

Now merge the conditions, and we get the solution for the first part:

if(date("D",$idate)!="Sun" && date("D",$idate)!="Sat" && ($idate%86400)>=(86400/24*8.5)&&($idate%86400)<=(86400/24*18.5)) 
$time1 = date('Y-m-d G:i', strtotime($idate1)+86400/12);

Note: You must use UTC+0 timezone in the script for this to work.

Rápli András
  • 3,869
  • 1
  • 35
  • 55