Jump to content

Recommended Posts

Tidied up the prototype's interface

 

function workingHours($jstart, $jfinish, $holidays=array())
   /*********
   * jstart - start time eg 2013-02-14 1 6:50:00
   * jfinish - finish time eg 2013-02-18 18:00:00
   * holidays- array of dates in yyyy-mm-dd format
   */
{
   $jobstart = new DateTime($jstart);
   $jobfinish = new DateTime($jfinish);

   $inc = DateInterval::createFromDateString('next weekday');
   $dp = new DatePeriod($jobstart, $inc, $jobfinish);

   $totalmins = 0;
   foreach ($dp as $day) {
    $datepart = $day->format('Y-m-d');
    $sod = clone $day;
    $sod->settime(9,0); // start of working day
    $eod = clone $day;
    $eod->settime(17,0);  //end of working day

    if (in_array($datepart, $holidays)) {
	    continue;
    }
    if ($datepart = $jobstart->format('Y-m-d')) {   // first day
	    $t = min(max($sod, $jobstart), $eod);    // ensure time between 9 - 5pm
	    list($h,$m) = explode(':', $eod->diff($t)->format('%h:%i'));
	    $totalmins += $h*60 + $m;
    }
    if ($datepart = $jobfinish->format('Y-m-d')) {   // last day
	    $t = min(max($sod, $jobfinish), $eod);    // ensure time between 9 - 5pm
	    if ($datepart = $jobfinish->format('Y-m-d')) {    // start date = finish date
		    list($h,$m) = explode(':', $eod->diff($t)->format('%h:%i'));
		    $totalmins -= ($h*60 + $m) ;
	    }
	    else {
		    list($h,$m) = explode(':', $sod->diff($t)->format('%h:%i'));
		    $totalmins += ($h*60 + $m) ;			    
	    }
    }
    if ($datepart != $jobstart->format('Y-m-d')
		    && $datepart != $jobfinish->format('Y-m-d')) {   // somewhere inbetween
	    $totalmins += 480;
    }

   }
   return $totalmins;
}

Thanks for all your input guys!

 

I've taken all your approaches and have come up with my own script.

I'll post it up once I've tested it for every scenario and optimized it.

 

Thanks again! I really didn't think I was going to get my head around this!

  • 1 month later...

Almost a month delay, sorry!

 

Here is the working script for Googlers reference ;D

You can paste it into a file and play around with the dates as it will echo what it is doing.

<?php

  date_default_timezone_set("GMT");
  
	$r = strtotime("03-05-2013 18:00:00");
	$n = strtotime("07-05-2013 19:00:00");
	//$n = strtotime(date("d-m-Y H:i:s", time()));

	$rTime = date("H:i:s", $r);
	$rTyme = date("His", $r);
	$rDate = date("d-m-Y", $r);
	$rDay =  date("w", $r);

  $nTime = date("H:i:s", $n);
	$nTyme = date("His", $n);
	$nDate = date("d-m-Y", $n);
	$nDay =  date("w", $n);

	$workdays = array(1,2,3,4,5);
	$holidays = array("01-01-2013", "29-03-2013", "01-04-2013", "06-05-2013", "27-05-2013", "26-08-2013",
	"25-12-2013", "26-12-2013",	"01-01-2014", "18-04-2014", "21-04-2014", "05-05-2014",
	"26-05-2014", "25-08-2014", "25-12-2014",	"26-12-2014", "01-01-2015", "03-04-2015",
	"06-04-2015", "04-05-2015", "25-05-2015", "31-08-2015",	"25-12-2015", "28-12-2015");
	// includes UK bank holidays until end of 2015

	echo '-- INPUT<br>';
	echo '$r = '.date("D d-m-Y H:i:s", $r).'<br>';
	echo '$n = '.date("D d-m-Y H:i:s", $n).'<br>';

	echo '<br>-- CHANGES<br>';
	
	# -- $r -------------------------------------
	
	# if $r is before 9am > move to 9am
	if($rTyme < "090000") {
		$r = strtotime("9am", $r);
		echo '$r is before 9am > move to 9am ('.date("D d-m-Y H:i:s", $r).')<br>';
  # elseif $r is after 5pm > move to 9am next workday
	} elseif($rTyme > "170000") {
		$r = strtotime("+1 weekday 9am", $r);
		echo '$r is after 5pm > move to 9am next workday ('.date("D d-m-Y H:i:s", $r).')<br>';
	}
	
	# if $r is a holiday > move to next workday 9am
	if(in_array(date("d-m-Y", $r), $holidays)) {
		$r = strtotime("+1 weekday 9am", $r);
		echo '$r is a holiday > move to next workday ('.date("D d-m-Y H:i:s", $r).')<br>';
		# Boxing Day Check
		if(date("d-m", $r) == "26-12" || date("d-m-Y", $r) == "28-12-2015") { 
			$r = strtotime("+1 weekday 9am", $r);
			echo '$r is boxing day > move to next workday ('.date("D d-m-Y H:i:s", $r).')<br>';
		}
	}

	# if $r is a weekend > move to next workday 9am
	if(!in_array(date("w", $r), $workdays)) {
		$r = strtotime("+1 weekday 9am", $r);
		echo '$r is a weekend > move to next workday ('.date("D d-m-Y H:i:s", $r).')<br>';
		# Holiday Check
		if(in_array(date("d-m-Y", $r), $holidays)) {
		  $r = strtotime("+1 weekday ".date('H:i:s', $r)."", $r);
		  echo '$r is a holiday > move to next workday ('.date("D d-m-Y H:i:s", $r).')<br>';
		}
	}
	
	# -- $n -------------------------------------
	
	# if $n is before 9am > move to 9am
	if($nTyme < "090000") {
		$n = strtotime("9am", $n);
		echo '$n is before 9am > move to 9am ('.date("D d-m-Y H:i:s", $n).')<br>';
  # elseif $n is after 5pm > move to 5pm
	} elseif($nTyme > "170000") {
		$n = strtotime("5pm", $n);
		echo '$n is after 5pm > move to 5pm ('.date("D d-m-Y H:i:s", $n).')<br>';
	}
	
	# if $n is a holiday > move to last workday 5pm
	if(in_array(date("d-m-Y", $n), $holidays)) {
		$n = strtotime("-1 weekday 5pm", $n);
		echo '$n is a holiday > move to last workday ('.date("D d-m-Y H:i:s", $n).')<br>';
		# Boxing Day Check
		if(date("d-m", $n) == "26-12" || date("d-m-Y", $n) == "28-12-2015") { 
			$n = strtotime("-1 weekday 5pm", $n);
			echo '$n is boxing day > move to last workday ('.date("D d-m-Y H:i:s", $n).')<br>';
		}
	}

	# if $n is a weekend > move to last workday 5pm
	if(!in_array(date("w", $n), $workdays)) {
		$n = strtotime("-1 weekday 5pm", $n);
		echo '$n is a weekend > move to last workday ('.date("D d-m-Y H:i:s", $n).')<br>';
		# Holiday Check
		if(in_array(date("d-m-Y", $n), $holidays)) {
		  $n = strtotime("-1 weekday 5pm", $n);
		  echo '$n is a holiday > move to last workday ('.date("D d-m-Y H:i:s", $n).')<br>';
		}
	}

	echo '<br>-- OUTPUT<br>';
	echo '$r = '.date("D d-m-Y H:i:s", $r).'<br>';
	echo '$n = '.date("D d-m-Y H:i:s", $n).'<br>';

  echo '<br>-- INPUT DIFFERENCE<br>';
  $diff = ($n - $r);
  echo 'Difference in seconds is '.$diff.'<br>';
  # work out hours, mins, secs
		# if $diff is negative > set to 0
		if($diff < 0) { 
		 $diff = 0; $h = 0; $m = 0; $s = 0;
		 echo '$diff is negative > set to 0<br>';
		} 

		echo '$n - $r = '.($n - $r).'<br>';
		$h = (int)($diff / 3600);
	  $m = (int)(($diff - $h*3600) / 60);
	  $s = (int)($diff - $h*3600 - $m*60);
		echo ''.$h.'h '.$m.'m '.$s.'s<br>';

	echo '<br>-- LOOP<br>';
	$r12 = strtotime("12pm", $r);
	$n12 = strtotime("12pm", $n);
	$daysBetween = ceil(abs($n12 - $r12) / 86400);
	echo '$daysBetween = '.$daysBetween.'<br>';
	 
	if($daysBetween == 0) {
	 
		// do nothing 	
  	  	
	} elseif ($daysBetween == 1) {
	 	
	 	echo 'Loop stage: '.date("d-m-Y H:i:s", $r).'<br>';

	 	# if $r is a valid workday and not a holiday
	 	if(in_array(date("w", $r), $workdays) && !in_array(date("d-m-Y", $r), $holidays)) {
			# remove 16 hours
			$diff-=57600;    
			echo '  > Removed 16 hours (is a valid day) for '.date("d-m-Y H:i:s", $r).'<br>';
		} else {
			# remove 24 hours
			$diff-=86400;
			echo '  > Removed 24 hours (isn\'t a valid day) for '.date("d-m-Y H:i:s", $r).'<br>';
		}
	 
	} elseif ($daysBetween >= 2) {
  	
    for($i=0;$i<$daysBetween;$i++) {
      
      echo 'Loop stage: '.date("d-m-Y H:i:s", $r).'<br>';

      # if $r is a valid workday and not a holiday
      if(in_array(date("w", $r), $workdays) && !in_array(date("d-m-Y", $r), $holidays)) {
      	echo '  > Removed 16 hours (is a valid day) for '.date("d-m-Y H:i:s", $r).'<br>';
      	$diff-=57600;
    	} else {
				# remove 24 hours
				$diff-=86400;
				echo '  > Removed 24 hours (isn\'t a valid day) for '.date("d-m-Y H:i:s", $r).'<br>';
			}

    	$r = strtotime("+1 day", $r);
      
    }
  	
	}

	echo '<br>-- OUTPUT DIFFERENCE<br>';
  echo 'Difference in seconds is '.$diff.'<br>';
  # work out hours, mins, secs
		# if $diff is negative > set to 0
		if($diff < 0) { 
		 $diff = 0; $h = 0; $m = 0; $s = 0;
		 echo '$diff is negative > set to 0<br>';
		} 

		echo '$n - $r = '.($n - $r).'<br>';
		$h = (int)($diff / 3600);
	  $m = (int)(($diff - $h*3600) / 60);
	  $s = (int)($diff - $h*3600 - $m*60);
		echo ''.$h.'h '.$m.'m '.$s.'s<br>';

?>
Edited by Clarkey
This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.