PHP - 在工作日和工作时间减去日期

时间:2012-12-01 02:14:23

标签: php datetime

我想计算两个日期之间的工作时间。所以我需要在星期六/星期日被忽略,我的工作时间是从早上9点到下午6点(9点到18点)。

我在网上搜索并尝试了一些变化,但似乎没有任何效果。任何人都可以帮忙吗?

我一直在看这个链接: Calculating working hours between two dates subtract non working hours and days from two given times in php calc the working hours between 2 dates in PHP

但是他们没有得到答案或答案提供不起作用。

感谢您的帮助

3 个答案:

答案 0 :(得分:2)

我在网上调整了一些功能,在这里根据我的需求进行了stackoverflow。他们在这里。

致电脚本:

date_default_timezone_set("Europe/Lisbon");
$startDate=strtotime('2012-11-30 00:15:33');
$endDate = strtotime('2012-12-05 10:15:00');

echo "Working hours from create date until due date -> ".seconds2human(work_hours_diff($startDate,$endDate));

人类可读的秒数(改编自http://snippetsofcode.wordpress.com/2012/08/25/php-function-to-convert-seconds-into-human-readable-format-months-days-hours-minutes/):

function seconds2human($ss) {
    $s = $ss%60;
    $m = floor(($ss%3600)/60);
    $h = floor(($ss)/3600);

    return "$h hours, $m minutes, $s seconds";
}

使用工作日和工作时间(改编自Calculating working hours between two dates)的子路径日期:

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(9, 17.5); // from 9:00 to 17:30 (8.5 hours)
    $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;

    //In case date1 is on same day of date2
    if (mktime(0,0,0,date('n', $date1), date('j', $date1), date('Y', $date1))==mktime(0,0,0,date('n', $date2), date('j', $date2), date('Y', $date2))) {
        //If its not working day, then return 0
        if (!in_array(date('w', $date1), $working_days)) return 0;

        $date0 = mktime($beg_h, $beg_m, 0, date('n', $date1), date('j', $date1), date('Y', $date1));
        $date3 = mktime($end_h, $end_m, 0, date('n', $date1), date('j', $date1), date('Y', $date1));

        if ($date1<$date0) {
            if ($date2<$date0) return 0;
            $date1 = $date0;
            if ($date2>$date3) $date2=$date3;
            return $date2-$date1;
        }
        if ($date1>$date3) return 0;
        if ($date2>$date3) $date2=$date3;
        return $date2-$date1;
    }

    //setup the very next first working time stamp
    if (!in_array(date('w',$current_date) , $working_days)) {
        // the current day is not a working day

        // the current time stamp is set at the beginning 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, 0, 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 beginning 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, 0, date('n',$current_date), date('j',$current_date), date('Y',$current_date) );
    $seconds = $date0-$current_date;

    // 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 ) {
        if (in_array(date('w',$current_date) , $working_days) ) $days++; // it's a working day
        $current_date += 24*3600; // next day
    }
    $days--; //because we've already count the first day (in $seconds)

    // check if end's timestamp is inside working hours
    $date0 = mktime( $beg_h, $beg_m, 0, date('n',$date2), date('j',$date2), date('Y',$date2) );
    if ((!in_array(date('w', $date2), $working_days)) || ($date2 < $date0)) {
        // it's before, so nothing more !
    } else {
        // is it after ?
        $date3 = mktime( $end_h, $end_m, 0, 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;
        $seconds += $tmp;
     }

    // calculate the working days in seconds
    $seconds += 3600*($working_hours[1]-$working_hours[0])*$days;

    return $sign * $seconds;
}

答案 1 :(得分:1)

我知道现在为时已晚,但我想这个问题还没有解决,我制作的代码可以帮助其他人解决同样的问题。这段代码只会增加工作日,因此,它将跳过午餐时间,周六和周日。

<?php 
function recursivoHorarioComercial($data)
{
$hora =  date("H", strtotime($data));
if($hora >= 18){
    $arrHorarios = array('18'=>'15','19'=>'14','20'=>'13','21'=>'12','22'=>'11','23'=>'10','00'=>'9','01'=>'8','02'=>'7',);
    $minutes = (60 * $arrHorarios[$hora]);
    $data = date("Y-m-d H:i:s", strtotime("+".$minutes." minutes", strtotime($data)));
}
$diaSemana = date("l", strtotime($data));
if($diaSemana == "Saturday"){
    $extraMinutes = (2 * 24 * 60);
    $data = date("Y-m-d H:i:s", strtotime("+".$extraMinutes." minutes", strtotime($data)));
} elseif($diaSemana == "Saturday"){
    $extraMinutes = (1 * 24 * 60);
    $data = date("Y-m-d H:i:s", strtotime("+".$extraMinutes." minutes", strtotime($data)));
}
$horaFim = date("H", strtotime($data));
return $data;
}
function incrementMinutes($data,$minutes)
{
$hours = floor($minutes / 60);
$minutes = ($minutes % 60);
$hid = 8;
$days = floor($hours/$hid);
$horaINi =  date("H", strtotime($data));
$hours = $hours - ($days * $hid);
$data = date("Y-m-d H:i:s", strtotime("+".$minutes." minutes", strtotime($data)));
$data = recursivoHorarioComercial($data);
$data = date("Y-m-d H:i:s", strtotime("+".$hours." hours", strtotime($data)));
$data = recursivoHorarioComercial($data);
for ($i = 1; $i <= $days; $i++){
    $data = date("Y-m-d H:i:s", strtotime("+1 day", strtotime($data)));
    $data = recursivoHorarioComercial($data);
}
$horaFim = date("H", strtotime($data));
if($horaINi <= 12 && $horaFim >= 12 ){
    $data = date("Y-m-d H:i:s", strtotime("+60 minutes", strtotime($data)));
}
return $data;
}

$date = "2016-04-06 09:00:00";
$minutos =  24 * 60; //increase 24 hours
echo "Now: ".$data."<br />";
echo "<h2>Modified</h2>";
echo incrementMinutes($date,$minutos)."<br />";


?>

我刚刚测试了这段代码,它运行正常。我希望这可以帮助任何人。

再见

答案 2 :(得分:0)

我知道我参加晚会很晚,但是我试图找到答案,花了几个小时来创建自己的答案,我没有说这是完美的,如果有人想修改我的代码以使其更简洁,请放心。仍然有一些要更改的地方,但是可以。我已经用Carbon来协助约会了。

    function getWorkingHoursDifference($start,$end){


// Declare Business Hours Start
$BusinessHoursStart = '08:30:00';

// Declare Business Hours Start
$BusinessHoursEnd = '17:00:00';

// Set Full Day Span // *Need to Calc from above
$fullDayMinutes = 8.5*60;

// Declare Exclusions
$exclusions = ['Saturday', 'Sunday'];

// Declare Start Time
$TimeStart  = Carbon::parse($start);

// Declare End Time
$TimeEnd    = Carbon::parse($end);

// Create Start Date
$DateStart  = Carbon::parse(date_format($TimeStart, 'Y-m-d'));

// Create End Date
$DateEnd    = Carbon::parse(date_format($TimeEnd, 'Y-m-d'));

// Create Period Span
$period = CarbonPeriod::create($DateStart, $DateEnd);

// Create Period Array
$period  = $period->toArray();

// Set Day Counter
$dayCount = 0;

// Set Loop Counter
$loopCount = 0;

// Total Minutes
$totalMinutes = 0;


foreach ($period as $date) {$dayCount++;}

    // Debugging
        //echo '<table class="table"><thead><th>LoopCount</th><th>Period Date</th><th>Day</th><th>Day Start</th><th>Day End</th><th>Minutes</th></thead>';

        foreach ($period as $date) {

        $dayOnly        = date_format($date, 'Y-m-d');
        $dayOnlyName    = date_format($date, 'l');
        $dayStart       = Carbon::parse($dayOnly.$BusinessHoursStart);
        $dayEnd         = Carbon::parse($dayOnly.$BusinessHoursEnd);

                // Clean Minutes
                $minutes = 0;
                // Loop Counter
                $loopCount++;

                // Check Excluded Days
                if(in_array($dayOnlyName, $exclusions)){$minutes = 0;}

                // Check if its a single day
                elseif($loopCount == 1 && $dayCount == 1){
                    if($TimeStart < $dayStart && $TimeEnd > $dayStart && $TimeEnd < $dayEnd){$minutes = $dayStart->diffInMinutes($TimeEnd);}
                    // If the time start is after business hours then 0
                    elseif($TimeStart > $dayEnd){$minutes = 0;}
                    // If the time start is after start of the day, but before closing hours
                    elseif($TimeStart > $dayStart){$minutes = $TimeStart->diffInMinutes($TimeEnd);}

                }

                // First Day
                elseif($loopCount == 1){
                    // If the Time Start is before business hours, count as a full day.
                    if($TimeStart < $dayStart){$minutes = $fullDayMinutes;}
                    // If the time start is after business hours then 0
                    elseif($TimeStart > $dayEnd){$minutes = 0;}
                    // If the time start is after start of the day, but before closing hours
                    elseif($TimeStart > $dayStart){$minutes = $TimeStart->diffInMinutes($dayEnd);}
                }

                // Last Day (loopCounter Matches Total Day Counter)
                elseif($loopCount == $dayCount){
                    // If the Time is before the start of the business day
                    if($TimeEnd< $dayStart){$minutes = 0;}
                    // If the End Time is after the day end then full day is counted
                    elseif($TimeEnd > $dayEnd){$minutes = $fullDayMinutes;}
                    // If the End time is after the start but before the end of business hours, work out the difference
                    elseif($TimeEnd > $dayStart){$minutes = $dayStart->diffInMinutes($TimeEnd);}
                }

                // All other days in the middle
                else{$minutes = $fullDayMinutes;}

                // Debugging
                //echo '<tr><td>'.$loopCount.'</td><td>'.$date.'</td><td>'.$dayOnlyName.'</td><td>'.$dayStart.'</td><td>'.$dayEnd.'</td><td>'.$minutes.'</td></tr>';

                $totalMinutes = $totalMinutes + $minutes;

            }



        //echo '</table>';

        return $totalMinutes;
}