PHP – вычесть даты в рабочие дни и часы работы

Я хочу рассчитать рабочее время между двумя датами. Поэтому мне нужно, чтобы в субботу и воскресенье меня игнорировали, а мое рабочее время – с 9:00 до 18:00 (с 9:00 до 18:00).

Я искал в Интернете и пробовал некоторые варианты, но ничего не работает. Любой может помочь?

Я смотрел на эти ссылки: вычисление рабочего времени между двумя датами вычитает нерабочие часы и дни с двух заданных времен в php calc рабочее время между двумя датами в PHP

Но или они не получили ответа или ответа, если он не работает.

Спасибо за любую помощь

Я адаптировал некоторые функции в Интернете и здесь, в 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"; } 

Даты субтракта по рабочим дням и рабочим часам (адаптированы из расчета рабочего времени между двумя датами ):

 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; } с 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; } 

Я знаю, что уже слишком поздно, но я думаю, что эта проблема еще не решена, и я создал код, который может помочь другим с той же проблемой. Этот код просто увеличивает рабочие дни, поэтому он пропускает время обеда, субботу и воскресенье.

 <?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("Ymd H:i:s", strtotime("+".$minutes." minutes", strtotime($data))); } $diaSemana = date("l", strtotime($data)); if($diaSemana == "Saturday"){ $extraMinutes = (2 * 24 * 60); $data = date("Ymd H:i:s", strtotime("+".$extraMinutes." minutes", strtotime($data))); } elseif($diaSemana == "Saturday"){ $extraMinutes = (1 * 24 * 60); $data = date("Ymd 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("Ymd H:i:s", strtotime("+".$minutes." minutes", strtotime($data))); $data = recursivoHorarioComercial($data); $data = date("Ymd H:i:s", strtotime("+".$hours." hours", strtotime($data))); $data = recursivoHorarioComercial($data); for ($i = 1; $i <= $days; $i++){ $data = date("Ymd H:i:s", strtotime("+1 day", strtotime($data))); $data = recursivoHorarioComercial($data); } $horaFim = date("H", strtotime($data)); if($horaINi <= 12 && $horaFim >= 12 ){ $data = date("Ymd 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 />"; ?> 

Я только что протестировал этот код, и он работает нормально. Я надеюсь, что это может помочь кому угодно.

до свидания