PHP calc price with different time range cost

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();

?>```

Share on other sites

Look into both using relative time formats such as new DateTime('monday midnight') to get your boundaries and datetime::diff() to get your durations.

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
```

Share on other sites

just tested, calc result not correct.

the correct count for below time1,time2, should be = 588+128 = \$716

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```

Share on other sites

amending

Edited by kit123321
amending
Share on other sites

Thanks for your reply Barand, pls ignore above information, my mistake.

is it possible to add calculating summary in script?

Edited by kit123321
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

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```

Share on other sites

• 2 weeks later...

do you have any idea?

Share on other sites

What have you tried to get the total?

Share on other sites

i still have no idea how to breakdown the date range into column automatically. any hint?

Share on other sites

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
Share on other sites

2 hours ago, kit123321 said:

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

What date range? What columns?

Can you explain the process you are having difficulty with?

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.

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)

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.

Share on other sites

like this right hand size output is what i want.

\$time1(Start time) & \$time2(End time) are variables, so the \$rentals array should be automatically value from \$time1,2.

Share on other sites

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

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>';```

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 ...

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
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.

Pic2 - incorrect if more than 1 day.

Share on other sites

The rows that are output are the peak and off-peak for each day.

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 |```

Join the conversation

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

Reply to this topic...

×   Pasted as rich text.   Restore formatting

Only 75 emoji are allowed.