[php] 영업일 계산

PHP에서 “영업일”을 추가하는 방법이 필요합니다. 예를 들어 금요일 12/5 + 영업일 3 일 = 수요일 12/10입니다.

최소한 주말을 이해하려면 코드가 필요하지만 이상적으로는 미국 연방 공휴일도 고려해야합니다. 필요한 경우 무차별 대입으로 해결책을 찾을 수 있다고 확신하지만 더 우아한 접근 방식이 있기를 바랍니다. 누군가?

감사.



답변

다음 은 PHP 매뉴얼의 date () 함수 페이지에 대한 사용자 의견의 함수입니다. 윤년 지원을 추가하는 주석의 이전 기능을 개선 한 것입니다.

시작일과 종료일을 그 사이에있을 수있는 공휴일 배열과 함께 입력하면 작업 일이 정수로 반환됩니다.

<?php
//The function returns the no. of business days between two dates and it skips the holidays
function getWorkingDays($startDate,$endDate,$holidays){
    // do strtotime calculations just once
    $endDate = strtotime($endDate);
    $startDate = strtotime($startDate);


    //The total number of days between the two dates. We compute the no. of seconds and divide it to 60*60*24
    //We add one to inlude both dates in the interval.
    $days = ($endDate - $startDate) / 86400 + 1;

    $no_full_weeks = floor($days / 7);
    $no_remaining_days = fmod($days, 7);

    //It will return 1 if it's Monday,.. ,7 for Sunday
    $the_first_day_of_week = date("N", $startDate);
    $the_last_day_of_week = date("N", $endDate);

    //---->The two can be equal in leap years when february has 29 days, the equal sign is added here
    //In the first case the whole interval is within a week, in the second case the interval falls in two weeks.
    if ($the_first_day_of_week <= $the_last_day_of_week) {
        if ($the_first_day_of_week <= 6 && 6 <= $the_last_day_of_week) $no_remaining_days--;
        if ($the_first_day_of_week <= 7 && 7 <= $the_last_day_of_week) $no_remaining_days--;
    }
    else {
        // (edit by Tokes to fix an edge case where the start day was a Sunday
        // and the end day was NOT a Saturday)

        // the day of the week for start is later than the day of the week for end
        if ($the_first_day_of_week == 7) {
            // if the start date is a Sunday, then we definitely subtract 1 day
            $no_remaining_days--;

            if ($the_last_day_of_week == 6) {
                // if the end date is a Saturday, then we subtract another day
                $no_remaining_days--;
            }
        }
        else {
            // the start date was a Saturday (or earlier), and the end date was (Mon..Fri)
            // so we skip an entire weekend and subtract 2 days
            $no_remaining_days -= 2;
        }
    }

    //The no. of business days is: (number of weeks between the two dates) * (5 working days) + the remainder
//---->february in none leap years gave a remainder of 0 but still calculated weekends between first and last day, this is one way to fix it
   $workingDays = $no_full_weeks * 5;
    if ($no_remaining_days > 0 )
    {
      $workingDays += $no_remaining_days;
    }

    //We subtract the holidays
    foreach($holidays as $holiday){
        $time_stamp=strtotime($holiday);
        //If the holiday doesn't fall in weekend
        if ($startDate <= $time_stamp && $time_stamp <= $endDate && date("N",$time_stamp) != 6 && date("N",$time_stamp) != 7)
            $workingDays--;
    }

    return $workingDays;
}

//Example:

$holidays=array("2008-12-25","2008-12-26","2009-01-01");

echo getWorkingDays("2008-12-22","2009-01-02",$holidays)
// => will return 7
?>


답변

두 날짜 사이에 휴일없는 근무일 수를 가져옵니다 .

사용 예 :

echo number_of_working_days('2013-12-23', '2013-12-29');

산출:

3

함수:

function number_of_working_days($from, $to) {
    $workingDays = [1, 2, 3, 4, 5]; # date format = N (1 = Monday, ...)
    $holidayDays = ['*-12-25', '*-01-01', '2013-12-23']; # variable and fixed holidays

    $from = new DateTime($from);
    $to = new DateTime($to);
    $to->modify('+1 day');
    $interval = new DateInterval('P1D');
    $periods = new DatePeriod($from, $interval, $to);

    $days = 0;
    foreach ($periods as $period) {
        if (!in_array($period->format('N'), $workingDays)) continue;
        if (in_array($period->format('Y-m-d'), $holidayDays)) continue;
        if (in_array($period->format('*-m-d'), $holidayDays)) continue;
        $days++;
    }
    return $days;
}


답변

도움이 될 date () 함수에 대한 몇 가지 인수가 있습니다 . 날짜 ( “w”)를 체크하면 일요일은 0부터 토요일은 6까지 요일에 대한 숫자가 표시됩니다. 그래서 .. 아마도 ..

$busDays = 3;
$day = date("w");
if( $day > 2 && $day <= 5 ) { /* if between Wed and Fri */
  $day += 2; /* add 2 more days for weekend */
}
$day += $busDays;

이것은 하나의 가능성에 대한 대략적인 예일뿐입니다 ..


답변

휴일 계산은 각 주에서 비표준입니다. 어려운 비즈니스 규칙이 필요하지만 여전히 대략적인 표준 만 얻을 수있는 은행 신청서를 작성 중입니다.

/**
 * National American Holidays
 * @param string $year
 * @return array
 */
public static function getNationalAmericanHolidays($year) {


    //  January 1 - New Year’s Day (Observed)
    //  Calc Last Monday in May - Memorial Day  strtotime("last Monday of May 2011");
    //  July 4 Independence Day
    //  First monday in september - Labor Day strtotime("first Monday of September 2011")
    //  November 11 - Veterans’ Day (Observed)
    //  Fourth Thursday in November Thanksgiving strtotime("fourth Thursday of November 2011");
    //  December 25 - Christmas Day        
    $bankHolidays = array(
          $year . "-01-01" // New Years
        , "". date("Y-m-d",strtotime("last Monday of May " . $year) ) // Memorial Day
        , $year . "-07-04" // Independence Day (corrected)
        , "". date("Y-m-d",strtotime("first Monday of September " . $year) ) // Labor Day
        , $year . "-11-11" // Veterans Day
        , "". date("Y-m-d",strtotime("fourth Thursday of November " . $year) ) // Thanksgiving
        , $year . "-12-25" // XMAS
        );

    return $bankHolidays;
}


답변

$startDate = new DateTime( '2013-04-01' );    //intialize start date
$endDate = new DateTime( '2013-04-30' );    //initialize end date
$holiday = array('2013-04-11','2013-04-25');  //this is assumed list of holiday
$interval = new DateInterval('P1D');    // set the interval as 1 day
$daterange = new DatePeriod($startDate, $interval ,$endDate);
foreach($daterange as $date){
if($date->format("N") <6 AND !in_array($date->format("Y-m-d"),$holiday))
$result[] = $date->format("Y-m-d");
}
echo "<pre>";print_r($result);


답변

날짜에 영업일을 추가하는 기능입니다.

 function add_business_days($startdate,$buisnessdays,$holidays,$dateformat){
  $i=1;
  $dayx = strtotime($startdate);
  while($i < $buisnessdays){
   $day = date('N',$dayx);
   $date = date('Y-m-d',$dayx);
   if($day < 6 && !in_array($date,$holidays))$i++;
   $dayx = strtotime($date.' +1 day');
  }
  return date($dateformat,$dayx);
 }

 //Example
 date_default_timezone_set('Europe\London');
 $startdate = '2012-01-08';
 $holidays=array("2012-01-10");
 echo '<p>Start date: '.date('r',strtotime( $startdate));
 echo '<p>'.add_business_days($startdate,7,$holidays,'r');

또 다른 게시물은 getWorkingDays (php.net 주석에서 여기에 포함됨)에 대해 언급했지만 일요일에 시작하여 근무일에 끝내면 중단되는 것 같습니다.

다음 사용 (이전 게시물의 getWorkingDays 함수를 포함해야 함)

 date_default_timezone_set('Europe\London');
 //Example:
 $holidays = array('2012-01-10');
 $startDate = '2012-01-08';
 $endDate = '2012-01-13';
 echo getWorkingDays( $startDate,$endDate,$holidays);

결과를 4가 아닌 5로 제공합니다.

Sun, 08 Jan 2012 00:00:00 +0000 weekend
Mon, 09 Jan 2012 00:00:00 +0000
Tue, 10 Jan 2012 00:00:00 +0000 holiday
Wed, 11 Jan 2012 00:00:00 +0000
Thu, 12 Jan 2012 00:00:00 +0000
Fri, 13 Jan 2012 00:00:00 +0000 

위의 생성을 위해 다음 함수가 사용되었습니다.

     function get_working_days($startDate,$endDate,$holidays){
      $debug = true;
      $work = 0;
      $nowork = 0;
      $dayx = strtotime($startDate);
      $endx = strtotime($endDate);
      if($debug){
       echo '<h1>get_working_days</h1>';
       echo 'startDate: '.date('r',strtotime( $startDate)).'<br>';
       echo 'endDate: '.date('r',strtotime( $endDate)).'<br>';
       var_dump($holidays);
       echo '<p>Go to work...';
      }
      while($dayx <= $endx){
       $day = date('N',$dayx);
       $date = date('Y-m-d',$dayx);
       if($debug)echo '<br />'.date('r',$dayx).' ';
       if($day > 5 || in_array($date,$holidays)){
        $nowork++;
     if($debug){
      if($day > 5)echo 'weekend';
      else echo 'holiday';
     }
       } else $work++;
       $dayx = strtotime($date.' +1 day');
      }
      if($debug){
      echo '<p>No work: '.$nowork.'<br>';
      echo 'Work: '.$work.'<br>';
      echo 'Work + no work: '.($nowork+$work).'<br>';
      echo 'All seconds / seconds in a day: '.floatval(strtotime($endDate)-strtotime($startDate))/floatval(24*60*60);
      }
      return $work;
     }

    date_default_timezone_set('Europe\London');
     //Example:
     $holidays=array("2012-01-10");
     $startDate = '2012-01-08';
     $endDate = '2012-01-13';
//broken
     echo getWorkingDays( $startDate,$endDate,$holidays);
//works
     echo get_working_days( $startDate,$endDate,$holidays);

휴일을 가져와 …


답변

더 간단한이 기능을 사용해 볼 수 있습니다.

function getWorkingDays($startDate, $endDate)
{
    $begin = strtotime($startDate);
    $end   = strtotime($endDate);
    if ($begin > $end) {

        return 0;
    } else {
        $no_days  = 0;
        while ($begin <= $end) {
            $what_day = date("N", $begin);
            if (!in_array($what_day, [6,7]) ) // 6 and 7 are weekend
                $no_days++;
            $begin += 86400; // +1 day
        };

        return $no_days;
    }
}