php获取N天后的日期,排除周末与节假日加上调休日

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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值