Jump to content

PHP calc price with different time range cost


kit123321
 Share

Recommended Posts

My objective.

$timestamp1 = rental start time, $timestamp2 rental end time, in order to calc price.
Price calc based on weekday and weekend timerange.
Example: start: Fri 1700 end: Fri 1900 = 88+118 = $206
I don't know how to calc the duration within different timerange, to use different price cost by hour.

$week_day = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'];
$weekend_day = ['Sat', 'Sun'];
$price_weekday_hour = 88;       // weekday 0200-1800
$price_weekday_peakhour = 118;  // weekday 1800-0200
$price_weekend_hour = 98;       // weekend 0200-1800
$price_weekend_peakhour = 128;  // weekend 1800-0200

 

<?php

class priceCalculator
{
    public $start;

    public $end;

    public function __construct($timestamp1, $timestamp2)
    {
        $this->start = $timestamp1;
        $this->end = $timestamp2;
    }

    public function calculate()
    {
        if ($this->isPeakHour() && $this->isWeekend()){
            // calculate
        }
    }

    /**
     * true = peak
     * false = normal
     *
     * @return bool
     */
    private function isPeakHour()
    {
        $startdateH = intval(date("H", $this->start));
        $enddateH = intval(date("H", $this->end));

        if ($startdateH > 18 && $enddateH < 2){
            return true;
        }
        return false;
    }

    /**
     * true = weekend
     * false = weekday
     *
     * @return bool
     */
    private function isWeekend()
    {
        $weekDay = date('w', $this->end);
        return ($weekDay == 0 || $weekDay == 6);
    }
}

$timestamp1 = strtotime("2022-03-12 16:12:00");
$timestamp2 = strtotime("2022-03-12 18:31:00");

$instance = new PriceCalculator($timestamp1, $timestamp2);
$instance->calculate();

?>

 

Link to comment
Share on other sites

Here's one way

class PriceCalculator
{
    private $start;
    private $end;
    private $price = [
                      0 => [ 98, 128],
                      1 => [ 88, 118],
                      2 => [ 88, 118],
                      3 => [ 88, 118],
                      4 => [ 88, 118],
                      5 => [ 88, 118],
                      6 => [ 98, 128]
                     ];
    
    public function __construct ($time1, $time2)
    {
        $this->start = new DateTime($time1);
        $this->end   = new DateTime($time2);
    }
    
    public function calculate()
    {
        $total = 0;
        $dp = new DatePeriod($this->start, new DateInterval('PT1M'), $this->end );
        foreach ($dp as $min) {
            $day = $min->format('w');
            $peak = '02' <= $min->format('H') && $min->format('H') < '18' ? 0 : 1;
            $total += $this->price[$day][$peak]/60;
        }

        return number_format($total, 2);
    }
}

$time1 = "2022-03-12 16:12:00";
$time2 = "2022-03-12 18:31:00";

$instance = new PriceCalculator($time1, $time2);
echo $instance->calculate();                                 // 242.53

 

  • Like 2
Link to comment
Share on other sites

imagine that you go rental a table. from Friday 12:00 to Saturday 12:00 = total 24 hours.

so should be = $88(weekday 1200-1800) *6 + $118(weekday 1800-0000) *6 + $128(weekend 0000-0200) *2+ $98(weekend 0200-1800) *10

= $2,472

time different price calc as below.

$week_day = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'];
$weekend_day = ['Sat', 'Sun'];
$price_weekday_hour = 88;       // weekday 0200-1800
$price_weekday_peakhour = 118;  // weekday 1800-0200
$price_weekend_hour = 98;       // weekend 0200-1800
$price_weekend_peakhour = 128;  // weekend 1800-0200

 

Link to comment
Share on other sites

Like this? ...

$rentals = [
             [ "2022-04-08 12:00:00", "2022-04-08 18:00:00" ],
             [ "2022-04-08 18:00:00", "2022-04-09 00:00:00" ],
             [ "2022-04-09 00:00:00", "2022-04-09 02:00:00" ],
             [ "2022-04-09 02:00:00", "2022-04-09 18:00:00" ]
           ];
echo '<pre>';
foreach ($rentals as $times) {
    $instance = new PriceCalculator($times[0], $times[1]);
    printf('%s | %s | %10s<br>', $times[0], $times[1], $instance->calculate());
}
echo '</pre>';

giving

2022-04-08 12:00:00 | 2022-04-08 18:00:00 |     528.00
2022-04-08 18:00:00 | 2022-04-09 00:00:00 |     708.00
2022-04-09 00:00:00 | 2022-04-09 02:00:00 |     256.00
2022-04-09 02:00:00 | 2022-04-09 18:00:00 |   1,568.00

NOTE: 02:00 to 18:00 is not 10 hours as in your example calculations

Link to comment
Share on other sites

Yes, you correct that my example calculations mistake, thanks for correction.

and Yes, that's what i need for the cost breakdown, but $time1 and $time2 are variable.

for example.

$time1 = "2022-04-11 16:05:00";
$time2 = "2022-04-11 18:12:00";

 

$rentals = [
             [ "2022-04-11 16:05:00", "2022-04-11 18:00:00" ],
             [ "2022-04-11 18:00:00", "2022-04-11 18:12:00" ]
           ];
echo '<pre>';
foreach ($rentals as $times) {
    $instance = new PriceCalculator($times[0], $times[1]);
    printf('%s | %s | %10s<br>', $times[0], $times[1], $instance->calculate());
}
echo '</pre>';

 

is it possible that the output automatically like this:
 

192.27
2022-04-11 16:05:00 | 2022-04-11 18:00:00 |     168.67
2022-04-11 18:00:00 | 2022-04-11 18:12:00 |      23.60

 

Link to comment
Share on other sites

  • 2 weeks later...

do you actually care if the breakdown lists the specific time part or would something that looks like the following, which is  simpler to code, tell you what you want to know -

Array
(
    [2022-04-08] => Array
        (
            [Norm] => 528
            [Peak] => 708
        )

    [2022-04-09] => Array
        (
            [Peak] => 256
            [Norm] => 1568
        )

)

 

Edited by mac_gyver
Link to comment
Share on other sites

it appears that the OP is asking for any single rental instance to be automatically broken down by amount per day, per rate.

his later examples aren't for x different rentals, but for one rental broken down into those date-time parts.

Link to comment
Share on other sites

2 minutes ago, mac_gyver said:

it appears that the OP is asking for any single rental instance to be automatically broken down by amount per day, per rate.

Where does it say that? All their examples given show a date range and a total price for that range. (Plus the recent request for a grand total)

Link to comment
Share on other sites

3 minutes ago, Barand said:

Where does it say that?

first in a question and $time1 = ... $time2 =... values buried in a picture of code in this post -

On 4/7/2022 at 9:44 PM, kit123321 said:

is it possible to add calculating summary in script? 

then in a non-picture example in this post -

On 4/10/2022 at 8:57 PM, kit123321 said:

for example.

$time1 = "2022-04-11 16:05:00";
$time2 = "2022-04-11 18:12:00";

the $time1 and $time2 are the start/end of one rental instance. the date-time ranges the OP listed in those examples are between those $time1 and $time2 values, with a break at midnight, so the resulting ranges are per day, pre rate on each day, for that specific rental period.

Link to comment
Share on other sites

6 minutes ago, mac_gyver said:

please post the actual code and output in the forum, using the <> menu button. pictures are impossible to use as input for testing.

i am sorry about that, since i would like you to check the output.

 

<?php

class PriceCalculator
{
    private $start;
    private $end;
    private $price = [
                      0 => [ 98, 128],
                      1 => [ 88, 118],
                      2 => [ 88, 118],
                      3 => [ 88, 118],
                      4 => [ 88, 118],
                      5 => [ 88, 118],
                      6 => [ 98, 128]
                     ];
    
    public function __construct ($time1, $time2)
    {
        $this->start = new DateTime($time1);
        $this->end   = new DateTime($time2);
    }
    
    public function calculate()
    {
        $total = 0;
        $dp = new DatePeriod($this->start, new DateInterval('PT1M'), $this->end );
        foreach ($dp as $min) {
            $day = $min->format('w');
            $peak = '02' <= $min->format('H') && $min->format('H') < '18' ? 0 : 1;
			$total += $this->price[$day][$peak]/60;
        }

        return number_format($total, 2);
    }
}

$time1 = "2022-04-11 16:05:00";
$time2 = "2022-04-11 18:12:00";

$instance = new PriceCalculator($time1, $time2);
echo $instance->calculate();                                 // 242.53

$rentals = [
             [ "2022-04-11 16:05:00", "2022-04-11 18:00:00" ],
             [ "2022-04-11 18:00:00", "2022-04-11 18:12:00" ]
           ];
echo '<pre>';
foreach ($rentals as $times) {
    $instance = new PriceCalculator($times[0], $times[1]);
    printf('%s | %s | %10s<br>', $times[0], $times[1], $instance->calculate());
}
echo '</pre>';

 

Link to comment
Share on other sites

3 hours ago, kit123321 said:

i still have no idea how to breakdown the date range into column automatically

I am beginning to understand. When you say "column" you really mean "row".

I thought you wanted to process multiple rentals (from a database table, for example), but what you want is to process a single rental but break it down into multiple peak and off-peak periods.

I'll await your answer to @mac_gyver's earlier question ...

 

Link to comment
Share on other sites

This may be what you want (who knows?)

class PriceCalculator
{
    private $start;
    private $end;
    private $price = [
                      0 => [ 98, 128],
                      1 => [ 88, 118],
                      2 => [ 88, 118],
                      3 => [ 88, 118],
                      4 => [ 88, 118],
                      5 => [ 88, 118],
                      6 => [ 98, 128]
                     ];
    public $periods = [];
    public $total = 0;
    
    public function __construct ($time1, $time2)
    {
        $this->start = new DateTime($time1);
        $this->end   = new DateTime($time2);
    }
    
    public function calculate()
    {
        $total = 0;
        $dp = new DatePeriod($this->start, new DateInterval('PT1M'), $this->end );
        $prevday = $prevpk = null;
        foreach ($dp as $min) {
            $day = $min->format('w');
            $peak = '02' <= $min->format('H') && $min->format('H') < '18' ? 0 : 1;
            if ($prevday != $min->format('Y-m-d') || $prevpk != $peak) {
                if (!isset($this->periods[$min->format('Y-m-d')][$peak])) {
                    $this->periods[$min->format('Y-m-d')][$peak] = ['start' => $min->format('H:i:s'), 'end' => null, 'dow' => $min->format('D'), 'price' => 0];
                }
                $prevday = $min->format('Y-m-d');
                $prevpk = $peak;
            }
            $this->periods[$prevday][$prevpk]['end'] = $min->modify('+1 minute')->format('H:i:s');
            $this->periods[$prevday][$prevpk]['price'] += $this->price[$day][$prevpk]/60;
            $this->total += $this->price[$day][$prevpk]/60;
        }

    }
}

$time1 = "2022-04-08 12:00:00";
$time2 = "2022-04-09 18:00:00";

$instance = new PriceCalculator($time1, $time2);
$instance->calculate();
    
echo number_format($instance->total, 2) . '<br><pre>';
foreach ($instance->periods as $date => $darr) {
    foreach ($darr as $pk => $arr) {
        printf ('| %s | %s | %s | %s | %-8s | %10.2f |<br>', $date
                                                           , $arr['dow']
                                                           , $arr['start']
                                                           , $arr['end']
                                                           , $pk ? 'Peak' : 'Off-peak'
                                                           , $arr['price']
                                                           );
    }
}   
echo '</pre>';

Giving

3,060.00
| 2022-04-08 | Fri | 12:00:00 | 18:00:00 | Off-peak |     528.00 |
| 2022-04-08 | Fri | 18:00:00 | 00:00:00 | Peak     |     708.00 |
| 2022-04-09 | Sat | 00:00:00 | 02:00:00 | Peak     |     256.00 |
| 2022-04-09 | Sat | 02:00:00 | 18:00:00 | Off-peak |    1568.00 |

 

Edited by Barand
code correction
Link to comment
Share on other sites

Yeah, Barand. you are correct. sorry my mistake that i am talking row, not column.

but i find that, when the period more than one day, the calc not correct.

Pic1 - correct if only 1 day.

image.thumb.png.166bdfd6a33b6ea2e8c87feefca0d64f.png

 

Pic2 - incorrect if more than 1 day.

image.thumb.png.0918e3f84abb0515a3b5b068218faa05.png

Link to comment
Share on other sites

You might prefer this version

<?php
class PriceCalculator
{
    private $start;
    private $end;
    private $price = [
                      0 => [ 98, 128],
                      1 => [ 88, 118],
                      2 => [ 88, 118],
                      3 => [ 88, 118],
                      4 => [ 88, 118],
                      5 => [ 88, 118],
                      6 => [ 98, 128]
                     ];
    public $periods = [];
    public $total = 0;
    
    public function __construct ($time1, $time2)
    {
        $this->start = new DateTime($time1);
        $this->end   = new DateTime($time2);
    }
    
    public function calculate()
    {
        $total = 0;
        $dp = new DatePeriod($this->start, new DateInterval('PT1M'), $this->end );
        $prevday = $prevpk = $prevh = null;
        foreach ($dp as $min) {
            $day = $min->format('w');
            $peak = '02' <= $min->format('H') && $min->format('H') < '18' ? 0 : 1;
            if ($prevday != $min->format('Y-m-d') || $prevpk != $peak) {
                if (!isset($this->periods[$min->format('d H')])) {
                    $this->periods[$min->format('d H')] = ['start' => $min->format('H:i:s'), 
                                                           'end' => null, 
                                                           'dow' => $min->format('D'),
                                                           'peak' => $peak,
                                                           'date' => $min->format('Y-m-d'),
                                                           'price' => 0 
                                                           ];
                }
                $prevday = $min->format('Y-m-d');
                $prevpk = $peak;
                $prevh = $min->format('d H');
            }
            $this->periods[$prevh]['end'] = $min->modify('+1 minute')->format('H:i:s');
            $this->periods[$prevh]['price'] += $this->price[$day][$prevpk]/60;
            $this->total += $this->price[$day][$prevpk]/60;
        }

    }
}

$time1 = "2022-04-23 18:00:00";
$time2 = "2022-04-25 18:00:00";

$instance = new PriceCalculator($time1, $time2);
$instance->calculate();
    
echo number_format($instance->total, 2) . '<br><pre>';
foreach ($instance->periods as $arr) {
        printf ('| %s | %s | %s - %s | %-8s | %10.2f |<br>', $arr['date']
                                                           , $arr['dow']
                                                           , $arr['start']
                                                           , $arr['end']
                                                           , $arr['peak'] ? 'Peak' : 'Off-peak'
                                                           , $arr['price']
                                                           );
}   
echo '</pre>';

giving

5,004.00
| 2022-04-23 | Sat | 18:00:00 - 00:00:00 | Peak     |     768.00 |
| 2022-04-24 | Sun | 00:00:00 - 02:00:00 | Peak     |     256.00 |
| 2022-04-24 | Sun | 02:00:00 - 18:00:00 | Off-peak |    1568.00 |
| 2022-04-24 | Sun | 18:00:00 - 00:00:00 | Peak     |     768.00 |
| 2022-04-25 | Mon | 00:00:00 - 02:00:00 | Peak     |     236.00 |
| 2022-04-25 | Mon | 02:00:00 - 18:00:00 | Off-peak |    1408.00 |

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.