php获取N天后的日期,排除周末与节假日加上调休日
代码如下
.
/**
* 求取从某日起经过一定天数后的日期,
* 排除周六周日和节假日加上调休日
* @param $start int|string 开始日期
* @param $offset int 经过天数
* @param $exception string|array 节假日
* @param $allow string|array 调休日
* @return string
* examples:输入(2021-01-09,36,''),得到2021-03-09
*/
function getendday( $start='now', $offset=0, $exception='', $allow='' )
{
date_default_timezone_set('prc');
//先计算不排除周六周日及节假日的结果
if (is_numeric($start)){
$starttime = $start;
}else{
$starttime = strtotime($start);
}
$endtime = $starttime + $offset * 24 * 3600;
$end = date('Y-m-d', $endtime);
//然后计算周六周日引起的偏移
$weekday = date('w', $starttime);//得到星期值:0-6
if ($weekday == 0){
//0是星期天
$weekday = 7;
}
$remain = $offset % 7;
$newoffset = 2 * ($offset - $remain) / 7;//每一周需重新计算两天
if ($remain > 0) {//周余凑整
$tmp = $weekday + $remain;
if ($tmp >= 7) {
$newoffset += 2;
} else if ($tmp == 6) {
$newoffset += 1;
}
//考虑当前为周六周日的情况
if ($weekday == 6) {
$newoffset -= 1;
} else if ($weekday == 7) {
$newoffset -= 2;
}
}
//再计算节假日引起的偏移
if (is_array($exception)) {//多个节假日
foreach ($exception as $day) {
$tmp_time = strtotime($day);
if ($tmp_time > $starttime && $tmp_time <= $endtime) {//在范围(a,b]内
$weekday_t = date('w', $tmp_time);
if ($weekday_t <= 5 && $weekday_t != 0) {//防止节假日与周末重复
$newoffset += 1;
}
}
}
}else {//单个节假日
if (!empty($exception)) {
$tmp_time = strtotime($exception);
if ($tmp_time > $starttime && $tmp_time <= $endtime) {
$weekday_t = date('w', $tmp_time);
if ($weekday_t <= 5 && $weekday_t != 0) {
$newoffset += 1;
}
}
}
}
//再计算调休日引起的偏移
if (is_array($allow)) {//多个调休日
foreach ($allow as $day) {
$tmp_time = strtotime($day);
if ($tmp_time > $starttime && $tmp_time <= $endtime) {//在范围(a,b]内
$weekday_t = date('w', $tmp_time);//得到星期值:0-6
if ($weekday_t == 6 || $weekday_t == 0) {
//若调休日是星期六、星期日
$newoffset -= 1;
}
}
}
}else {//单个调休日
if (!empty($allow)) {
$tmp_time = strtotime($allow);
if ($tmp_time > $starttime && $tmp_time <= $endtime) {
$weekday_t = date('w', $tmp_time);
if ($weekday_t == 6 || $weekday_t == 0) {
//若调休日是星期六、星期日
$newoffset -= 1;
}
}
}
}
//根据偏移天数,递归做等价运算
if($newoffset > 0){
#echo "[{$start} -> {$offset}] = [{$end} -> {$newoffset}]"."<br />n";
return getendday($end,$newoffset,$exception,$allow);
}else{
return $end;
}
}