2013-05-27 63 views
0

簡報:用PHP計算營業日:這是否準確?

我試圖計算兩個日期自定義項目管理系統我建立的工作日。以下是我所做的,如下所示。它似乎工作正常,但我不知道它有多準確,是否應該使用它。任何反饋將不勝感激!

CODE

<?php 

    # date variables: 
    date_default_timezone_set('Asia/Kuwait'); 
    $date['start'] = date('Y-m-d H:i:s'); 
    $date['end'] = '2013-12-01 08:00:00'; 
    $date['off'] = array('Friday','Saturday'); # usual days off in Kuwait) 

    # calculate the difference: 
    $date_s = new DateTime($date['start']); 
    $date_e = new DateTime($date['end']); 
    $interval = $date_s->diff($date_e); 

    # obtain relevant values: 
    $remaining_days = $interval->format('%r%a'); 
    $remaining_weeks = floor($remaining_days/7); 
    $weekend_days = ($remaining_weeks*count($date['off'])); 

    # additional holidays (just an example): 
    $extra_holidays_array = array 
    (
     'holiday 1' => '2013-06-24 00:00:00', 
     'holiday 2' => '2013-06-25 00:00:00', 
     'holiday 3' => '2013-07-01 00:00:00', 
     'holiday 4' => '2013-08-24 00:00:00' 
    ); 

    # check if a real holiday: 
    $extra_holidays = 0; 
    foreach($extra_holidays_array as $check_date) 
    { 
     $day_of_holiday = date('l', strtotime($check_date)); 
     if(! in_array($day_of_holiday,$date['off'])){ $extra_holidays++; } 
    } 

    # total holidays: 
    $total_holidays = ($weekend_days+$extra_holidays); 

    # business days: 
    $business_days_nh = ($remaining_days-$weekend_days); # NO extra holidays 
    $business_days_wh = ($remaining_days-$weekend_days-$extra_holidays); # WITH extra holidays 

?> 

<ul> 
<li>Current Date: <?php echo $date['start']; ?></li> 
<li>Deadline Date: <?php echo $date['end']; ?></li> 
</ul> 
<ul> 
<li>Remaining Days: <?php echo $remaining_days; ?></li> 
<li>Remaining Weeks: <?php echo $remaining_weeks; ?></li> 
</ul> 
<ul> 
<li>Usual Holidays: <?php echo $weekend_days; ?></li> 
<li>Extra Holidays: <?php echo $extra_holidays; ?></li> 
<li>Total Holidays: <?php echo $total_holidays; ?></li> 
</ul> 
<ul> 
<li>Business Days (Before Holidays): <?php echo $business_days_nh; ?></li> 
<li>Business Days (After Holidays): <?php echo $business_days_wh; ?></li> 
</ul> 
+1

您是否有一套覆蓋邊緣案例的單元測試? –

+1

對不起,我不明白。你究竟是什麼意思?如果我所假設的是正確的,那麼如果開始日期等於或大於結束日期,我會得到負值,這對我來說不是問題。 –

+0

我的意思是,許多開發人員還編寫單元測試以使用代碼,測試它們可以運行以證明代碼正常工作。這樣,他們不需要詢問其他人是否有效,但如果所有測試都通過,就可以證明它是有效的。 –

回答

1

我寫了一個函數在以前的項目爲這個確切的目的:

這裏是作爲參數的內容:

  • $啓動 - 啓動Unix時間戳(你可以使用strtotime('2013年1月1日)獲得時間戳
  • $ end - E第二UNIX時間戳
  • 可選$假期 - 日期的數組數爲節假日(IE節假日等),它使用strtotime()轉換日期
  • 可選$ returnAsArray - 返回工作日時間戳列表,或者乾脆數量工作日

重要 它的重要,要知道,時間戳給出的應該是一天的開始時間戳,例如:

要使用2013年1月1日作爲一個時間戳,使用值的:mktime(0, 0, 0, 1, 1, 2013);

function networkDays($start, $end, array $holidays = array(), $returnAsArray = false) 
{ 
    if(!is_int($start)){ 
     trigger_error('Parameter 1 expected to be integer timestamp. ' . ucfirst(gettype($start)) . ' given.', E_USER_WARNING); 
     return false; 
    } 

    if(!is_int($end)){ 
     trigger_error('Parameter 2 expected to be integer timestamp. ' . ucfirst(gettype($start)) . ' given.', E_USER_WARNING); 
     return false; 
    } 

    if(!is_array($holidays)){ 
     $holidays = array(); 
     trigger_error('Parameter 3 expected to be Array. ' . ucfirst(gettype($holidays)) . ' given.', E_USER_NOTICE); 
    } 

    if(!is_bool($returnAsArray)){ 
     trigger_error('Parameter 4 expected to be Boolean. ' . ucfirt(gettype($returnAsArray)) . ' given.', E_USER_WARNING); 
     return false; 
    } 


    if($start>=$end){ 
     $nEnd = $start; 
     $nStart = $end; 

     $start = $nStart; 
     $end = $nEnd; 
    } 


    foreach($holidays as $key => $holiday) 
    { 
     $holidays[$key] = strtotime($holiday); 
    } 


    $numberOfDays = ceil(((($end-$start)/60)/60)/24); 

    $networkDay = 0; 
    $networkDayArray = array(); 

    for($d = 0; $d < $numberOfDays; $d++) 
    { 
     $dayTimestamp = $start+(86400*$d); 

     if(date('N',$dayTimestamp)<6 && !in_array($dayTimestamp,$holidays)) 
     { 
      $networkDay += 1; 
      $networkDayArray[] = $dayTimestamp; 
     } 
    } 


    if($returnAsArray) 
    { 
     return $networkDayArray; 
    } else { 
     return $networkDay; 
    } 
}