Can some one help me write a function that calculates the number of working hours between two dates but want to exclude the time when the request had a status of "On Hold".
So lets say the request came in at 3PM friday and was closed at 3PM Wednesday, and working hours are from 8AM to 5PM pacific (Mon thru Friday)...Total working hours will be 27 hours...but if the request remained on hold from Monday 3PM till Tuesday 3PM...Actual work time on the request really becomes 18 hours instead of 27 hours.
I have recently started working on PHP and have been assigned this task which is very confusing to me. Please help
Calculate work time with an accuracy of 1 minute.
WARNING: This function can take many seconds to load as it does a loop for every minute between the time span.
<?php
$request = array(
'start' => '3PM Nov 29 2013',
'end' => '3PM Dec 4 2013'
);
echo calculate_work($request);
/**
* Calculate work time by looping through every minute
* @param array $request start to end time
* @return int work time in minutes
*/
function calculate_work($request)
{
$start = strtotime($request['start']);
$end = strtotime($request['end']);
$work_time = 0;
/* Add 1 minute to the start so that we don't count 0 as a minute */
for ($time = $start + 60; $time <= $end; $time += 60)
{
// Weekends
if (date('D', $time) == 'Sat' OR date('D', $time) == 'Sun')
continue;
// Non Working Hours
if (date('Hi', $time) <= '0800' OR date('Hi', $time) > '1700')
continue;
// On Hold
if ($time > strtotime('3PM Dec 2 2013') AND $time <= strtotime('3PM Dec 3 2013'))
continue;
$work_time++;
}
// Divide by 60 to turn minutes into hours
return $work_time / 60;
}
All you have to do is get the total time elapsed, then substract the non-working hours.
You can use dateTime and datePeriod php objects for that (requires php 5.3)
Here a small script to do what you want (but you will have probably to adapt for your needs)
<?php
ini_set('display_errors', 'on');
define('DAY_WORK', 32400); // 9 * 60 * 60
define('HOUR_START_DAY', '08:00:00');
define('HOUR_END_DAY', '17:00:00');
// get begin and end dates of the full period
$date_begin = '2013-11-29 15:00:00';
$date_end = '2013-12-03 15:00:00';
// keep the initial dates for later use
$d1 = new DateTime($date_begin);
$d2 = new DateTime($date_end);
// and get the datePeriod from the 1st to the last day
$period_start = new DateTime($d1->format('Y-m-d 00:00:00'));
$period_end = new DateTime($d2->format('Y-m-d 23:59:59'));
$interval = new DateInterval('P1D');
//$interval = new DateInterval('weekdays'); // 1 day interval to get all days between the period
$period = new DatePeriod($period_start, $interval, $period_end);
$worked_time = 0;
$nb = 0;
// for every worked day, add the hours you want
foreach($period as $date){
$week_day = $date->format('w'); // 0 (for Sunday) through 6 (for Saturday)
if (!in_array($week_day,array(0, 6)))
{
// if this is the first day or the last dy, you have to count only the worked hours
if ($date->format('Y-m-d') == $d1->format('Y-m-d'))
{
$end_of_day_format = $date->format('Y-m-d '.HOUR_END_DAY);
$d1_format = $d1->format('Y-m-d H:i:s');
$end_of_day = new DateTime($end_of_day_format);
$diff = $end_of_day->diff($d1)->format("%H:%I:%S");
$diff = split(':', $diff);
$diff = $diff[0]*3600 + $diff[1]*60 + $diff[0];
$worked_time += $diff;
}
else if ($date->format('Y-m-d') == $d2->format('Y-m-d'))
{
$start_of_day = new DateTime($date->format('Y-m-d '.HOUR_START_DAY));
$d2_format = $d2->format('Y-m-d H:i:s');
$end_of_day = new DateTime($end_of_day_format);
$diff = $start_of_day->diff($d2)->format('%H:%I:%S');
$diff = split(':', $diff);
$diff = $diff[0]*3600 + $diff[1]*60 + $diff[0];
$worked_time += $diff;
}
else
{
// otherwise, just count the full day of work
$worked_time += DAY_WORK;
}
}
if ($nb> 10)
die("die ".$nb);
}
echo sprintf('Works from %s to %s, You worked %d hour(s)', $date_begin, $date_end, $worked_time/60/60);
/**
* Get the total working hours in seconds between 2 dates..
* @param DateTime $start Start Date and Time
* @param DateTime $end Finish Date and Time
* @param array $working_hours office hours for each weekday (0 Monday, 6 Sunday), Each day must be an array containing a start/finish time in seconds since midnight.
* @return integer
* @link https://github.com/RCrowt/working-hours-calculator
*/
function getWorkingHoursInSeconds(DateTime $start, DateTime $end, array $working_hours)
{
$seconds = 0; // Total working seconds
// Calculate the Start Date (Midnight) and Time (Seconds into day) as Integers.
$start_date = clone $start;
$start_date = $start_date->setTime(0, 0, 0)->getTimestamp();
$start_time = $start->getTimestamp() - $start_date;
// Calculate the Finish Date (Midnight) and Time (Seconds into day) as Integers.
$end_date = clone $end;
$end_date = $end_date->setTime(0, 0, 0)->getTimestamp();
$end_time = $end->getTimestamp() - $end_date;
// For each Day
for ($today = $start_date; $today <= $end_date; $today += 86400) {
// Get the current Weekday.
$today_weekday = date('w', $today);
// Skip to next day if no hours set for weekday.
if (!isset($working_hours[$today_weekday][0]) || !isset($working_hours[$today_weekday][1])) continue;
// Set the office hours start/finish.
$today_start = $working_hours[$today_weekday][0];
$today_end = $working_hours[$today_weekday][1];
// Adjust Start/Finish times on Start/Finish Day.
if ($today === $start_date) $today_start = min($today_end, max($today_start, $start_time));
if ($today === $end_date) $today_end = max($today_start, min($today_end, $end_time));
// Add to total seconds.
$seconds += $today_end - $today_start;
}
return gmdate("H:i:s", $seconds);
}