Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calculating working hours between two dates

Tags:

date

php

time

I need a PHP method for calculating working hours between two dates based on a 8 hour working day and excluding weekends and bank holidays.

For example the difference between 2012-01-01T08:30:00 AND 2012-01-05T10:30:00 in working hours is actually 26 working hours because the first two days are weekend/bank holiday which just leaves 3 working days and the time differnce of 2 hours i.e. 3*8+2=26.

I have used @flamingLogos excellent answer to a previous question but cannot get it to take into account the time as well as date.

like image 284
user1156756 Avatar asked Jan 18 '12 17:01

user1156756


People also ask

What is the formula to calculate working hours?

Just multiply the hours worked per day by the number of days worked per week. If an employee works different schedules every day, then you will need to calculate hours worked for each day. You will then need to add up the total for each day to get their hours worked in a given week.

How do I calculate the number of hours between two dates in Excel?

Another simple technique to calculate the duration between two times in Excel is using the TEXT function: Calculate hours between two times: =TEXT(B2-A2, "h") Return hours and minutes between 2 times: =TEXT(B2-A2, "h:mm") Return hours, minutes and seconds between 2 times: =TEXT(B2-A2, "h:mm:ss")

How do you calculate work days between dates?

To calculate the number of working days between two dates, we must follow these steps: Count the number of days between the two dates. Subtract the number of weekend days between the two dates.


2 Answers

Function below calculates working hours between two dates, provided in text format such as '2013-11-27 13:40', taking work day hours from 9 to 17 (can be changed).

function get_working_hours($from,$to)
{
    // timestamps
    $from_timestamp = strtotime($from);
    $to_timestamp = strtotime($to);

    // work day seconds
    $workday_start_hour = 9;
    $workday_end_hour = 17;
    $workday_seconds = ($workday_end_hour - $workday_start_hour)*3600;

    // work days beetwen dates, minus 1 day
    $from_date = date('Y-m-d',$from_timestamp);
    $to_date = date('Y-m-d',$to_timestamp);
    $workdays_number = count(get_workdays($from_date,$to_date))-1;
    $workdays_number = $workdays_number<0 ? 0 : $workdays_number;

    // start and end time
    $start_time_in_seconds = date("H",$from_timestamp)*3600+date("i",$from_timestamp)*60;
    $end_time_in_seconds = date("H",$to_timestamp)*3600+date("i",$to_timestamp)*60;

    // final calculations
    $working_hours = ($workdays_number * $workday_seconds + $end_time_in_seconds - $start_time_in_seconds) / 86400 * 24;

    return $working_hours;
}

There are two additional functions. One returns work days array...

function get_workdays($from,$to) 
{
    // arrays
    $days_array = array();
    $skipdays = array("Saturday", "Sunday");
    $skipdates = get_holidays();

    // other variables
    $i = 0;
    $current = $from;

    if($current == $to) // same dates
    {
        $timestamp = strtotime($from);
        if (!in_array(date("l", $timestamp), $skipdays)&&!in_array(date("Y-m-d", $timestamp), $skipdates)) {
            $days_array[] = date("Y-m-d",$timestamp);
        }
    }
    elseif($current < $to) // different dates
    {
        while ($current < $to) {
            $timestamp = strtotime($from." +".$i." day");
            if (!in_array(date("l", $timestamp), $skipdays)&&!in_array(date("Y-m-d", $timestamp), $skipdates)) {
                $days_array[] = date("Y-m-d",$timestamp);
            }
            $current = date("Y-m-d",$timestamp);
            $i++;
        }
    }

    return $days_array;
}

and second - returns holidays array

function get_holidays() 
{
    // arrays
    $days_array = array();

    // You have to put there your source of holidays and make them as array...
    // For example, database in Codeigniter:
    // $days_array = $this->my_model->get_holidays_array();

    return $days_array;
}
like image 121
hajlabajla Avatar answered Oct 26 '22 22:10

hajlabajla


Maybe you can use this function :

function work_hours_diff($date1,$date2) {
    if ($date1>$date2) { $tmp=$date1; $date1=$date2; $date2=$tmp; unset($tmp); $sign=-1; } else $sign = 1;
    if ($date1==$date2) return 0;

    $days = 0;
    $working_days = array(1,2,3,4,5); // Monday-->Friday
    $working_hours = array(8.5, 17.5); // from 8:30(am) to 17:30
    $current_date = $date1;
    $beg_h = floor($working_hours[0]); $beg_m = ($working_hours[0]*60)%60;
    $end_h = floor($working_hours[1]); $end_m = ($working_hours[1]*60)%60;

    // setup the very next first working timestamp

    if (!in_array(date('w',$current_date) , $working_days)) {
        // the current day is not a working day

        // the current timestamp is set at the begining of the working day
        $current_date = mktime( $beg_h, $beg_m, 0, date('n',$current_date), date('j',$current_date), date('Y',$current_date) );
        // search for the next working day
        while ( !in_array(date('w',$current_date) , $working_days) ) {
            $current_date += 24*3600; // next day
        }
    } else {
        // check if the current timestamp is inside working hours

        $date0 = mktime( $beg_h, $beg_m, 0, date('n',$current_date), date('j',$current_date), date('Y',$current_date) );
        // it's before working hours, let's update it
        if ($current_date<$date0) $current_date = $date0;

        $date3 = mktime( $end_h, $end_m, 59, date('n',$current_date), date('j',$current_date), date('Y',$current_date) );
        if ($date3<$current_date) {
            // outch ! it's after working hours, let's find the next working day
            $current_date += 24*3600; // the day after
            // and set timestamp as the begining of the working day
            $current_date = mktime( $beg_h, $beg_m, 0, date('n',$current_date), date('j',$current_date), date('Y',$current_date) );
            while ( !in_array(date('w',$current_date) , $working_days) ) {
                $current_date += 24*3600; // next day
            }
        }
    }

    // so, $current_date is now the first working timestamp available...

    // calculate the number of seconds from current timestamp to the end of the working day
    $date0 = mktime( $end_h, $end_m, 59, date('n',$current_date), date('j',$current_date), date('Y',$current_date) );
    $seconds = $date0-$current_date+1;

    printf("\nFrom %s To %s : %d hours\n",date('d/m/y H:i',$date1),date('d/m/y H:i',$date0),$seconds/3600);

    // calculate the number of days from the current day to the end day

    $date3 = mktime( $beg_h, $beg_m, 0, date('n',$date2), date('j',$date2), date('Y',$date2) );
    while ( $current_date < $date3 ) {
        $current_date += 24*3600; // next day
        if (in_array(date('w',$current_date) , $working_days) ) $days++; // it's a working day
    }
    if ($days>0) $days--; //because we've allready count the first day (in $seconds)

    printf("\nFrom %s To %s : %d working days\n",date('d/m/y H:i',$date1),date('d/m/y H:i',$date3),$days);

    // check if end's timestamp is inside working hours
    $date0 = mktime( $beg_h, 0, 0, date('n',$date2), date('j',$date2), date('Y',$date2) );
    if ($date2<$date0) {
        // it's before, so nothing more !
    } else {
        // is it after ?
        $date3 = mktime( $end_h, $end_m, 59, date('n',$date2), date('j',$date2), date('Y',$date2) );
        if ($date2>$date3) $date2=$date3;
        // calculate the number of seconds from current timestamp to the final timestamp
        $tmp = $date2-$date0+1;
        $seconds += $tmp;
        printf("\nFrom %s To %s : %d hours\n",date('d/m/y H:i',$date2),date('d/m/y H:i',$date3),$tmp/3600);
    }

    // calculate the working days in seconds

    $seconds += 3600*($working_hours[1]-$working_hours[0])*$days;

    printf("\nFrom %s To %s : %d hours\n",date('d/m/y H:i',$date1),date('d/m/y H:i',$date2),$seconds/3600);

    return $sign * $seconds/3600; // to get hours
}

I put printf() to show what it is done (you can remove them)

You call it like that :

date_default_timezone_set("America/Los_Angeles");
$dt2 = strtotime("2012-01-01 05:25:00");
$dt1 = strtotime("2012-01-19 12:40:00");
echo work_hours_diff($dt1 , $dt2 );
like image 31
sly63 Avatar answered Oct 27 '22 00:10

sly63