Tôi biết mình đến dự tiệc muộn, nhưng tôi sử dụng bộ hàm cũ này của Marcos J. Montes để tìm ra ngày nghỉ và ngày làm việc. Ông đã dành thời gian để thêm một thuật toán từ năm 1876 cho Lễ Phục sinh và ông đã thêm tất cả các ngày lễ lớn của Hoa Kỳ. Điều này có thể dễ dàng được cập nhật cho các quốc gia khác.
//Usage
$days = 30;
$next_working_date = nextWorkingDay($days, $somedate);
//add date function
function DateAdd($interval, $number, $date) {
$date_time_array = getdate($date);
//die(print_r($date_time_array));
$hours = $date_time_array["hours"];
$minutes = $date_time_array["minutes"];
$seconds = $date_time_array["seconds"];
$month = $date_time_array["mon"];
$day = $date_time_array["mday"];
$year = $date_time_array["year"];
switch ($interval) {
case "yyyy":
$year+=$number;
break;
case "q":
$year+=($number*3);
break;
case "m":
$month+=$number;
break;
case "y":
case "d":
case "w":
$day+=$number;
break;
case "ww":
$day+=($number*7);
break;
case "h":
$hours+=$number;
break;
case "n":
$minutes+=$number;
break;
case "s":
$seconds+=$number;
break;
}
// echo "day:" . $day;
$timestamp= mktime($hours,$minutes,$seconds,$month,$day,$year);
return $timestamp;
}
// the following function get_holiday() is based on the work done by
// Marcos J. Montes
function get_holiday($year, $month, $day_of_week, $week="") {
if ( (($week != "") && (($week > 5) || ($week < 1))) || ($day_of_week > 6) || ($day_of_week < 0) ) {
// $day_of_week must be between 0 and 6 (Sun=0, ... Sat=6); $week must be between 1 and 5
return FALSE;
} else {
if (!$week || ($week == "")) {
$lastday = date("t", mktime(0,0,0,$month,1,$year));
$temp = (date("w",mktime(0,0,0,$month,$lastday,$year)) - $day_of_week) % 7;
} else {
$temp = ($day_of_week - date("w",mktime(0,0,0,$month,1,$year))) % 7;
}
if ($temp < 0) {
$temp += 7;
}
if (!$week || ($week == "")) {
$day = $lastday - $temp;
} else {
$day = (7 * $week) - 6 + $temp;
}
//echo $year.", ".$month.", ".$day . "<br><br>";
return format_date($year, $month, $day);
}
}
function observed_day($year, $month, $day) {
// sat -> fri & sun -> mon, any exceptions?
//
// should check $lastday for bumping forward and $firstday for bumping back,
// although New Year's & Easter look to be the only holidays that potentially
// move to a different month, and both are accounted for.
$dow = date("w", mktime(0, 0, 0, $month, $day, $year));
if ($dow == 0) {
$dow = $day + 1;
} elseif ($dow == 6) {
if (($month == 1) && ($day == 1)) { // New Year's on a Saturday
$year--;
$month = 12;
$dow = 31;
} else {
$dow = $day - 1;
}
} else {
$dow = $day;
}
return format_date($year, $month, $dow);
}
function calculate_easter($y) {
// In the text below, 'intval($var1/$var2)' represents an integer division neglecting
// the remainder, while % is division keeping only the remainder. So 30/7=4, and 30%7=2
//
// This algorithm is from Practical Astronomy With Your Calculator, 2nd Edition by Peter
// Duffett-Smith. It was originally from Butcher's Ecclesiastical Calendar, published in
// 1876. This algorithm has also been published in the 1922 book General Astronomy by
// Spencer Jones; in The Journal of the British Astronomical Association (Vol.88, page
// 91, December 1977); and in Astronomical Algorithms (1991) by Jean Meeus.
$a = $y%19;
$b = intval($y/100);
$c = $y%100;
$d = intval($b/4);
$e = $b%4;
$f = intval(($b+8)/25);
$g = intval(($b-$f+1)/3);
$h = (19*$a+$b-$d-$g+15)%30;
$i = intval($c/4);
$k = $c%4;
$l = (32+2*$e+2*$i-$h-$k)%7;
$m = intval(($a+11*$h+22*$l)/451);
$p = ($h+$l-7*$m+114)%31;
$EasterMonth = intval(($h+$l-7*$m+114)/31); // [3 = March, 4 = April]
$EasterDay = $p+1; // (day in Easter Month)
return format_date($y, $EasterMonth, $EasterDay);
}
function nextWorkingDay($number_days, $start_date = "") {
$day_counter = 0;
$intCounter = 0;
if ($start_date=="") {
$today = mktime(0, 0, 0, date("m") , date("d"), date("Y"));
} else {
$start_time = strtotime($start_date);
$today = mktime(0, 0, 0, date("m", $start_time) , date("d", $start_time), date("Y", $start_time));
}
while($day_counter < $number_days) {
$working_time = DateAdd("d", 1, $today);
$working_date = date("Y-m-d", $working_date);
if (!isWeekend($working_date) && !confirm_holiday(date("Y-m-d", strtotime($working_date))) ) {
$day_counter++;
}
$intCounter++;
$today = $working_time;
if ($intCounter > 1000) {
//just in case out of control?
break;
}
}
return $working_date;
}
function isWeekend($check_date) {
return (date("N", strtotime($check_date)) > 5);
}
function confirm_holiday($somedate="") {
if ($somedate=="") {
$somedate = date("Y-m-d");
}
$year = date("Y", strtotime($somedate));
$blnHoliday = false;
//newyears
if ($somedate == observed_day($year, 1, 1)) {
$blnHoliday = true;
}
if ($somedate == format_date($year, 1, 1)) {
$blnHoliday = true;
}
if ($somedate == format_date($year, 12, 31)) {
$blnHoliday = true;
}
//Martin Luther King
if ($somedate == get_holiday($year, 1, 1, 3)) {
$blnHoliday = true;
}
//President's
if ($somedate == get_holiday($year, 2, 1, 3)) {
$blnHoliday = true;
}
//easter
if ($somedate == calculate_easter($year)) {
$blnHoliday = true;
}
//Memorial
if ($somedate == get_holiday($year, 5, 1)) {
$blnHoliday = true;
}
//july4
if ($somedate == observed_day($year, 7, 4)) {
$blnHoliday = true;
}
//labor
if ($somedate == get_holiday($year, 9, 1, 1)) {
$blnHoliday = true;
}
//columbus
if ($somedate == get_holiday($year, 10, 1, 2)) {
$blnHoliday = true;
}
//thanks
if ($somedate == get_holiday($year, 11, 4, 4)) {
$blnHoliday = true;
}
//xmas
if ($somedate == format_date($year, 12, 24)) {
$blnHoliday = true;
}
if ($somedate == format_date($year, 12, 25)) {
$blnHoliday = true;
}
return $blnHoliday;
}