时间段重合计算问题

在工作中,碰到了一个实际案例需要计算两个时间段的重合问题。具体问题是根据租赁时间和免租期来计算租金,而且租金计价方式不确定(可能按年,按月,按天计算)。

时间段重合计算

在本次实际案例中,实际上为去除掉两个时间段的重复部分,暂时没想到什么好的办法,就采用了罗列各种情况分别处理的方法:

public function date_count($sdate,$edate,$fee_sdate,$fee_edate){

    //  判断合同是否设置免租期
    if(!empty($fee_sdate) && !empty($fee_edate)){
        //  设置了免租期,进行校验
        if(!api_check_date_format($fee_sdate) || !api_check_date_format($fee_edate)){
            //  此处校验时间戳格式是否正确
        }elseif($fee_sdate > $fee_edate){
            //  此处校验时间大小问题
        }

        if($fee_edate < $sdate || $fee_sdate > $edate){
            //  免租期和租期不重合
            $amount = $this->get_pay_amount($sdate,$edate);
        }elseif($fee_sdate <= $sdate && $edate <= $fee_edate){
            //  免租期包含租期   (fs---【s---e】---fe)
            $amount = 0;
        }elseif($sdate <= $fee_sdate && $fee_edate <= $edate){
            //  租期包含免租期   【s---(fs---fe)---e】
            if($sdate < $fee_sdate){
                $pay_edate = date("Y-m-d",strtotime("-1day",strtotime($fee_sdate)));
                $amount1 = $this->get_pay_amount($sdate,$pay_edate);
            }else{
                $amount1 = 0;
            }
            if($fee_edate < $edate){
                $pay_sdate = date("Y-m-d",strtotime("+1day",strtotime($fee_edate)));
                $amount2 = $this->get_pay_amount($pay_sdate,$edate);
            }else{
                $amount2 = 0;
            }
            //  此处两个四舍五入后的浮点数相加,可能导致精度不准确
            $amount = $amount1 + $amount2;
        }elseif($fee_sdate < $sdate && $sdate <= $fee_edate && $fee_edate < $edate){
            //  免租期和租期前半部分重合   (fs---【s---fe)---e】
            $pay_sdate = date("Y-m-d",strtotime("+1day",strtotime($fee_edate)));
            $amount = $this->get_pay_amount($pay_sdate,$edate);
        }elseif($sdate < $fee_sdate && $fee_sdate <= $edate && $edate < $fee_edate){
            //  免租期和租期后半部分重合   【s---(fs---e】---fe)
            $pay_edate = date("Y-m-d",strtotime("-1day",strtotime($fee_sdate)));
            $amount = $this->get_pay_amount($sdate,$pay_edate);
        }else{
            //  此处担心会出现自己没有考虑到的额外情况,代码进行反馈
        }
    }else{
        //  未设置免租期
        $amount = $this->get_pay_amount($sdate,$edate);
    }
    return $amount;
}

时间段计算年月日数量

顺带写下根据时间段来计算该时间段有几年,几月,几天的数量:

public function count_date_detail($sdate,$edate){
    $edate = date("Y-m-d",strtotime("+1day",strtotime($edate)));
    $date_arr = [
        'year_num'=>0,
        'month_num'=>0,
        'day_num'=>0
    ];

    $year_num = api_date_numbers(strtotime($sdate),strtotime($edate),'y');
    $new_edate = date("Y-m-d",strtotime("+".$year_num."years -1day",strtotime($sdate)));
    if($new_edate == $edate){
        $date_arr['year_num'] = $year_num;
        return $date_arr;
    }else{
        if($new_edate > $edate){
            $year_num -= 1;
        }
        $new_sdate = date("Y-m-d",strtotime("+".$year_num."years",strtotime($sdate)));

        //  计算剩余月数
        $month_num = api_date_numbers(strtotime($new_sdate),strtotime($edate),'m');
        $new_edate = date("Y-m-d",strtotime("+".$month_num."months -1day",strtotime($new_sdate)));
        if($new_edate == $edate){
            $date_arr['year_num'] = $year_num;
            $date_arr['month_num'] = $month_num;
            return $date_arr;
        }else{
            if($new_edate > $edate){
                $month_num -= 1;
            }
            $new_sdate = date("Y-m-d",strtotime("+".$month_num."months",strtotime($new_sdate)));

            //  计算剩余天数
            $day_num = api_date_numbers(strtotime($new_sdate),strtotime($edate),'d');
            $new_edate = date("Y-m-d",strtotime("+".$day_num."days",strtotime($new_sdate)));
            if($new_edate > $edate){
                $day_num -= 1;
            }elseif($new_edate < $edate){
                $day_num += 1;
            }

            $date_arr['year_num'] = $year_num;
            $date_arr['month_num'] = $month_num;
            $date_arr['day_num'] = $day_num;
            return $date_arr;
        }
    }
}

//  粗略计算有几年或者几月几天
function api_date_numbers($start,$end,$type='d'){
    //  日期格式为2020-01-01,start和end均为时间戳
    $start_m = date('Y-m-d',$start);
    $end_m = date('Y-m-d',$end);
    $date1 = explode('-',$start_m);
    $date2 = explode('-',$end_m);
    if ($type=='y'){
        //取绝对值,避免因年份大小产生的负值
        $number= abs($date1[0] - $date2[0]);
    }elseif ($type=='m'){
        //判断月份大小,进行相应加或减
        if($date1[1]<$date2[1]){
            $number= abs($date1[0] - $date2[0]) * 12 + abs($date1[1] - $date2[1]);
        }else{
            $number= abs($date1[0] - $date2[0]) * 12 - abs($date1[1] - $date2[1]);
        }
    }else{
        $time = $end-$start;
        $number = abs(intval($time/(3600*24)));
    }
    return $number;
}

如果有错误漏洞,或者更好的办法,欢迎大佬指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值