Calculate the number of hours in a given timeframe

2019-08-16 23:42发布

问题:

I have a booking system where users can book a room at any time, and for any number of continuous days. The booking is charged depending on the number of minutes the room is in use.

In the booking system, the start and end time is represented by two timestamps. e.g.

start_time = 1397124000
end_time = 1397129400

From this I can calculate the number of seconds booked, and therefore calculate a charge.

The problem I have is that I'd like to calculate a 50% discount on any bookings made out of peak times - before 8am, and after 6pm. Bookings can be made across these times (i.e. 7am-9am), and so the appropriate proportion should be discounted (50% discount on the 7-8am portion of the 7-9am booking).

My code for calculating this is getting extremely confusing and complicated, as there are several scenarios:

  1. The booking starts and ends during a discount period (e.g. 3am-7am - 4 hours discounted)
  2. The booking starts during a discount, but ends afterwards (e.g. 7am-9am - 1 hour discounted)
  3. The booking starts and ends during a period of non-discount (10am-5pm - no discount)
  4. The booking starts during a period of non-discount, but ends afterwards (5pm-10pm - 1 hour discounted)
  5. The booking spans an entire before-during-after discount period (2am-10pm - 10 hours discounted) or even more complicated (2am on Day 1 to 10pm on Day 5 - 50 hours discounted).

At the moment trying to work out what proportion of a booking is during these pre-8am, post-6pm discount period when only provided with a start and end timestamp is very difficult.

My code is a very large series of if and else statements testing against start and end times, but it is not robust against bookings that span more than one day and is otherwise very messy.

I'm looking for a method that can easily calculate what proportion of a booking is within a discounted time, that accounts for all possible scenarios. A difficult problem!

回答1:

After pondering many options, the following solution eventually occurred to me.

I wrote a function to move through the booking start and end times in 30 minute intervals, check to see if each time was within a discounted period:

function discount_period($timestamp) {
    $lowerTime = mktime (8,0,0,date("n", $timestamp), date("j", $timestamp), date("Y", $timestamp));
    $upperTime = mktime (18,0,0,date("n", $timestamp), date("j", $timestamp), date("Y", $timestamp));
    if (($timestamp < $lowerTime) || ($timestamp >= $upperTime)) {
            return true;
    }
    else {
            return false;   
    }
}

$discountmins = 0;
$nondiscountmins = 0;

for ($i = strtotime($billingResult->start_time); $i < strtotime($billingResult->end_time); $i += 1800) {
    if (discount_period($i)) {
        // This is within a discount period of at least 30 minutes
        $discountmins += 30;
    }
    else {
        $nondiscountmins +=30;  
    }
}
$discountedcost = ((($discountmins / 60) * $billingResult->cost_per_hr) * 0.5) / 100;
$nondiscountcost = (($nondiscountmins / 60) * $billingResult->cost_per_hr) / 100;

So it essentially checks to see if the next 30 minute window is within a discount period - if it is, it increments the discounted minute counter, or the non-discounted minute counter if not. At the end it them merely calculates the costs based on the number of minutes.