複製代碼 代碼如下:/*
| Author: Yang Yu <niceses@gmail.com>
| @param char|int $start_date 一個有效日期格式,例如:20091016,2009-10-16
| @param char|int $end_date 同上
| @return 給定日期之間的周末天數
*/
function get_weekend_days($start_date,$end_date){
if (strtotime($start_date) > strtotime($end_date)) list($start_date, $end_date) = array($end_date, $start_date);
$start_reduce = $end_add = 0;
$start_N = date('N',strtotime($start_date));
$start_reduce = ($start_N == 7) ? 1 : 0;
$end_N = date('N',strtotime($end_date));
in_array($end_N,array(6,7)) && $end_add = ($end_N == 7) ? 2 : 1;
$days = abs(strtotime($end_date) - strtotime($start_date))/86400 + 1;
return floor(($days + $start_N - 1 - $end_N) / 7) * 2 - $start_reduce + $end_add;
}
備忘:
最近寫給公司用的考勤系統,把其中的一個功能自動化,就是每個月的工作日(出勤天數)改為自動寫入,於是寫出以上函數,用來計算兩個日期內的周六周日總數,稍微解釋下吧,這個功能當然是用迴圈實現是最簡單的,從開始那天for到結束那天,中間只要是周六或周日,就++,最後輕易算出總和,但還是那句話,迴圈的效率實在是不好,尤其當時間跨度過長時,慘不忍睹。
我這個函數的基本思路是四個字:前補後砍。沒聽懂吧?我也覺得有點莫名其妙。。。就是取得開始日期的星期數,如果不足一周,則補上對應的天數,比如開始日期是星期3,那麼總天數就補上2天(星期1,星期2),如果開始日期是星期6,則補上5天,也就是6-1,就是函數中的$start_N - 1,如果開始日期恰好是周日,那麼補上6天的同時,最後的結果需要減去一天(周六),也就是函數中的 $start_reduce ,好了,現在“前補”解釋完了。下面講下“後砍”,顧名思義,就是將後面多餘的不足一周的天數,砍掉,例如,結束日期為星期3,那麼就從總天數裡減去3天,如果結束日期為星期6或者星期天,那麼減去6或7的同時,還要在最後補上1或2。
演算法沒什麼痛點,核心思想就是將這個時間段調整為7的整數,然後乘以2,在減去或加上多算和少算的周六或周日,得到的就是星期六和星期日的總和。最後算一段時間內的天數,不建議用date(z)來算,因為通用性會不好,涉及到跨年的問題,如果跨多年,還要考慮閏年的問題,倒不如這樣算來的直接。
改進記錄,加入$is_workday 參數,可以選擇是否返回工作日,預設是返回休息日 複製代碼 代碼如下:function get_weekend_days($start_date,$end_date,$is_workday = false){
if (strtotime($start_date) > strtotime($end_date)) list($start_date, $end_date) = array($end_date, $start_date);
$start_reduce = $end_add = 0;
$start_N = date('N',strtotime($start_date));
$start_reduce = ($start_N == 7) ? 1 : 0;
$end_N = date('N',strtotime($end_date));
in_array($end_N,array(6,7)) && $end_add = ($end_N == 7) ? 2 : 1;
$alldays = abs(strtotime($end_date) - strtotime($start_date))/86400 + 1;
$weekend_days = floor(($alldays + $start_N - 1 - $end_N) / 7) * 2 - $start_reduce + $end_add;
if ($is_workday){
$workday_days = $alldays - $weekend_days;
return $workday_days;
}
return $weekend_days;
}