订单时长计价之按时段计费

在一种项目中,订单的金额是以时长来计算价格的,比如共享单车、自助洗车这类的项目。订单一般有一个开始时间,有一个结束时间,然后用duration来计算订单总额。
一般来说有两种计价方式:

  • 一种是前x分钟多少钱,超时每分钟多少钱
  • 第二种是分闲忙时,不同的时间段内,每分钟是什么价格

今天介绍的是第二种,闲忙时,不同时段有不同价格来计费。其中有两个重点:

  1. 跨时段的情况
  2. 跨天的情况(暂时不考虑跨好几天的情况,只考虑跨两天)
class OrderModel 
{
	/**
	* 订单结算方法
	* $start_time  订单开始时间戳
	* $end_time 订单结束时间戳
	*/
	public function settlement($start_time,$end_time){
        //1 计算总价
        $amount = 0;
        /*判断是否跨天*/
        $startDate =  date("Y-m-d",  $start_time);
        $endDate =  date("Y-m-d",  $end_time);
        //把时间戳转为日期格式,如果不在同一天,则把时间分为2段
        if($startDate  < $endDate){	
            $day1_end= strtotime(date("Y-m-d 23:59:59",  $start_time));	//第一天的结束时间就是start_time日期的最后一分钟
            $day2_start= strtotime(date("Y-m-d 00:00:00",  $end_time));	//第二天的开始时间
           //将时段分为 【开始时间至开始日期的最后一秒】和【结束日期的第一秒至结束时间】
           $amount += $this->computePriceSectionOnDay($start_time,$day1_end);
           $amount += $this->computePriceSectionOnDay($day2_start,$end_time);
        }else{
        	//不跨天的情况
            $amount = $this->computePriceSectionOnDay($start_time,$end_time);
        }
        
		return $amount;
    }

	/**
     * 分时段计算价格,在一天之内,不考虑跨天情况。
     * (跨天的处理在上层方法)
     * @param $start_time
     * @param $end_time
     * @return int|null
     */
    private function computePriceSectionOnDay($start_time,$end_time){
        //从系统配置里获取时段计费规则 section_time=时间区间 section_price=区间价格/分钟
        $rates = [
            [
                "section_time"=>"00:00-09:59",
                "section_price"=>5
            ],
            [
                "section_time"=>"10:00-14:59",
                "section_price"=>8
            ],
            [
                "section_time"=>"15:00-23:59",
                "section_price"=>5
            ],
        ];
        // 遍历计费规则
        //如果跨2个区间,则用 区间1的endtime - 订单开始时间 = 落在区间一的时长,订单结束时间 - 区间2的starttime = 落在区间二的时长
        $amount = 0;
        $stemp_start = $start_time;  //用于截断时长时,标记新的计费开始时间点
        foreach ($rates as $rate) {
            $timeRange = explode('-', $rate['section_time']);
            $section_start = strtotime($timeRange[0]);
            $section_end = strtotime($timeRange[1]);
            //stemp_time 是否落在这个区间,yes,则开始计算费用
            if($stemp_start>=$section_start && $stemp_start < $section_end){
                if($end_time<= $section_end+1){
                    //最后一个区间,包含了订单结束时间
                    $amount += $this->computePriceTool($stemp_start,$end_time,$rate['section_price']);
                    Log::debug('包含订单结束,金额为'.$amount);
                    break;
                }else{
                    //订单end_time大于该区间的结束时间,则跨时段了,截断计价
                    $amount += $this->computePriceTool($stemp_start,$section_end+1,$rate['section_price']);
                    //下一个循环的开始时间是区间的结束+1秒
                    $stemp_start = $section_end+1;
                }
            }
        }
        return $amount;
    }

    /**
     * 计算价格辅助方法
     * @param $start_time 开始时间戳 11位到秒
     * @param $end_time 结束时间戳
     * @param $price 价格,每分钟计价
     * @return void
     */
    private function computePriceTool($start_time,$end_time,$price){
        $duration = $end_time - $start_time;
        $amount = $duration * $price/60;
        return $amount;
    }
}
    ```
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值