2012-06-21 93 views
2
我使用此功能(我在這個論壇上找到)來計算範圍之間的工作日天數

PHP計算基於功能的日期爲工作日

<?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("$startdate","$enddate",$holidays) 
?> 

現在,我想稍微擴展一下這個功能。如果我從開始日期開始添加X個工作日,我想要生成日期。例如說我有保存價值

$workingdays = "20"; 

一個變量和$startdate2012-06-01我想使這個函數計算的開始日期+ 20個工作日內將是2012-06-28。這可能嗎?

回答

8

我在使用下面的函數的同時做了類似的事情。這裏的關鍵是跳過週末,你可以延長這個跳過假期。

例子:

調用的函數 - >addDays(strtotime($startDate), 20, $skipdays,$skipdates = array())

<?php 
    function addDays($timestamp, $days, $skipdays = array("Saturday", "Sunday"), $skipdates = NULL) { 
     // $skipdays: array (Monday-Sunday) eg. array("Saturday","Sunday") 
     // $skipdates: array (YYYY-mm-dd) eg. array("2012-05-02","2015-08-01"); 
     //timestamp is strtotime of ur $startDate 
     $i = 1; 

     while ($days >= $i) { 
      $timestamp = strtotime("+1 day", $timestamp); 
      if ((in_array(date("l", $timestamp), $skipdays)) || (in_array(date("Y-m-d", $timestamp), $skipdates))) 
      { 
       $days++; 
      } 
      $i++; 
     } 

     return $timestamp; 
     //return date("m/d/Y",$timestamp); 
    } 
    ?> 

[編輯]:剛纔讀NETTUTS一個驚人的文章,希望這有助於http://net.tutsplus.com/tutorials/php/dates-and-time-the-oop-way/

+0

的功能你請解釋一下如何使用它?一般來說,我對PHP函數都很陌生。 – David

+0

調用函數 - > addDays(strtotime($ startDate),20,$ skipdays,$ skipdates = NULL); 它確定如果您發送$ val skipDays和$ skipDays的空vals,在這種情況下通過默認星期六,太陽和沒有額外的日期將被跳過 –

+0

如何將時間戳thingy轉換爲實際的Y-M-D日期?是的,我是一個新手.. – David

2

如果有人有興趣,我使用此功能將X個工作日添加到日期。該函數需要一個時間戳並返回一個時間戳。可以通過數組指定假期(如果在美國,則可以使用usBankHolidays())。

目前,假設週六和週日不是營業日,但可以輕鬆更改。

代碼

function addBusinessDays($date, $days, $holidays = array()) { 
    $output = new DateTime(); 
    $output->setTimestamp($date); 
    while ($days > 0) { 
     $weekDay = $output->format('N'); 

     // Skip Saturday and Sunday 
     if ($weekDay == 6 || $weekDay == 7) { 
      $output = $output->add(new DateInterval('P1D')); 
      continue; 
     } 

     // Skip holidays 
     $strDate = $output->format('Y-m-d'); 
     foreach ($holidays as $s) { 
      if ($s == $strDate) { 
       $output = $output->add(new DateInterval('P1D')); 
       continue 2; 
      } 
     } 

     $days--; 
     $output = $output->add(new DateInterval('P1D')); 
    } 
    return $output->getTimestamp(); 
} 

function usBankHolidays($format = 'datesonly') { 
    $output = array(
     array('2015-05-25', 'Memorial Day'), 
     array('2015-07-03', 'Independence Day'), 
     array('2015-09-07', 'Labor Day'), 
     array('2015-10-12', 'Columbus Day'), 
     array('2015-11-11', 'Veterans Day'), 
     array('2015-11-26', 'Thanksgiving Day'), 
     array('2015-12-25', 'Christmas Day'), 
     array('2016-01-01', 'New Year Day'), 
     array('2016-01-18', 'Martin Luther King Jr. Day'), 
     array('2016-02-15', 'Presidents Day (Washingtons Birthday)'), 
     array('2016-05-30', 'Memorial Day'), 
     array('2016-07-04', 'Independence Day'), 
     array('2016-09-05', 'Labor Day'), 
     array('2016-10-10', 'Columbus Day'), 
     array('2016-11-11', 'Veterans Day'), 
     array('2016-11-24', 'Thanksgiving Day'), 
     array('2016-12-25', 'Christmas Day'), 
     array('2017-01-02', 'New Year Day'), 
     array('2017-01-16', 'Martin Luther King Jr. Day'), 
     array('2017-02-20', 'Presidents Day (Washingtons Birthday)'), 
     array('2017-05-29', 'Memorial Day'), 
     array('2017-07-04', 'Independence Day'), 
     array('2017-09-04', 'Labor Day'), 
     array('2017-10-09', 'Columbus Day'), 
     array('2017-11-10', 'Veterans Day'), 
     array('2017-11-23', 'Thanksgiving Day'), 
     array('2017-12-25', 'Christmas Day'), 
     array('2018-01-01', 'New Year Day'), 
     array('2018-01-15', 'Martin Luther King Jr. Day'), 
     array('2018-02-19', 'Presidents Day (Washingtons Birthday)'), 
     array('2018-05-28', 'Memorial Day'), 
     array('2018-07-04', 'Independence Day'), 
     array('2018-09-03', 'Labor Day'), 
     array('2018-10-08', 'Columbus Day'), 
     array('2018-11-12', 'Veterans Day'), 
     array('2018-11-22', 'Thanksgiving Day'), 
     array('2018-12-25', 'Christmas Day'), 
     array('2019-01-01', 'New Year Day'), 
     array('2019-01-21', 'Martin Luther King Jr. Day'), 
     array('2019-02-18', 'Presidents Day (Washingtons Birthday)'), 
     array('2019-05-27', 'Memorial Day'), 
     array('2019-07-04', 'Independence Day'), 
     array('2019-09-02', 'Labor Day'), 
     array('2019-10-14', 'Columbus Day'), 
     array('2019-11-11', 'Veterans Day'), 
     array('2019-11-28', 'Thanksgiving Day'), 
     array('2019-12-25', 'Christmas Day'), 
     array('2020-01-01', 'New Year Day'), 
     array('2020-01-20', 'Martin Luther King Jr. Day'), 
     array('2020-02-17', 'Presidents Day (Washingtons Birthday)'), 
     array('2020-05-25', 'Memorial Day'), 
     array('2020-07-03', 'Independence Day'), 
     array('2020-09-07', 'Labor Day'), 
     array('2020-10-12', 'Columbus Day'), 
     array('2020-11-11', 'Veterans Day'), 
     array('2020-11-26', 'Thanksgiving Day'), 
     array('2020-12-25', 'Christmas Day '), 
    ); 

    if ($format == 'datesonly') { 
     $temp = array(); 
     foreach ($output as $item) { 
      $temp[] = $item[0]; 
     } 
     $output = $temp; 
    } 

    return $output; 
} 

用法:

$deliveryDate = addBusinessDays(time(), 7, usBankHolidays()); 
+0

儘量讓所有假期都動態:) –

+1

foreach $假期中存在一個錯誤。繼續是在foreach範圍內,而不是在範圍內,你必須繼續使用2. –

+0

@LucaS,非常感謝你發現這個錯誤。 –

0

使用this.lau_ function,我abble扭轉這種局面,對於減法日期,使用的有效期限。希望這可以幫助別人:

function subBusinessDays($date, $days, $holidays = array()) { 
      $output = new DateTime(); 
      $output->setTimestamp($date); 

      while ($days > 0) { 

       $output = $output->sub(new DateInterval('P1D')); 

       // Skip holidays 
       $strDate = $output->format('Y-m-d'); 
       if (in_array($strDate, $holidays)) { 
        // Skip Saturday and Sunday 
        $output = $output->sub(new DateInterval('P1D')); 
        continue; 
       } 

       $weekDay = $output->format('N'); 
       if ($weekDay <= 5) { 
        $days --; 
       } 

      } 

      return $output->getTimestamp(); 
     } 
0

從@ this.lau_回答重寫更簡單,更合乎邏輯算法,動態(固定)holydays

public function addBusinessDays($date, $days) { 

    $output = new DateTime(); 
    $output->setTimestamp($date); 

    while ($days > 0) { 

     $output = $output->add(new DateInterval('P1D')); 
     $weekDay = $output->format('N'); 
     $strDate = $output->format('Y-m-d'); 

     // Skip Saturday and Sunday 
     if ($weekDay == 6 || $weekDay == 7) { 

      continue; 

     } 

     // Skip holidays 
     $holidays = $this->_getHolidays();    

     foreach ($holidays as $holiday_date => $holiday_name) { 

      if ($holiday_date == $strDate) { 

       continue 2; 

      } 

     } 

     $days--; 

    } 

    return $output->getTimestamp(); 

} 



public function _getHolidays() { 

    $feste = array(
     date("Y") . "-01-01" => "Capodanno", 
     date("Y") . "-01-06" => "Epifania", 
     date("Y") . "-04-25" => "Liberazione", 
     date("Y") . "-05-01" => "Festa Lavoratori", 
     date("Y") . "-06-02" => "Festa della Repubblica", 
     date("Y") . "-08-15" => "Ferragosto", 
     date("Y") . "-11-01" => "Tutti Santi", 
     date("Y") . "-12-08" => "Immacolata", 
     date("Y") . "-12-25" => "Natale", 
     date("Y") . "-12-26" => "St. Stefano" 
    ); 

    return $feste; 

} 

呼叫與

$deliveryDate = addBusinessDays(time(), 7);