I am creating an application that charges a client based on time usage of a service. The problem is that the services can have double charge for a pre-specified time period of the day.
So let's say we have a service for printing documents and the charge for using the printer is 5€ per hour and 10€ between 23:00 and 02:00 in the morning. Also a client can rent the printer for as much time as he likes. This can be from 1 minute to months or even years.
Now the specific problem:
Let's say a client comes in my office to rent the printer for 55 hours. Also the rent starts at 20:00 at night.
So the charge must be for 43 hours in single charge and for 12 hours in double charge. Here are two example images:
Now, let me give you some extra info about the hours. In programming, each hour has a timestamp that it is time passed from January 1, 1970 00:00:00 to the time in seconds.
So the date July 05 2012 11:15:40 has the timestamp 1373022940 and the date July 05 2012 11:15:50 has the timestamp 1373022950
In the above example lets say that the first example placed in the date May 1, 2013, so the timestamp for 23:00 will be 1367449200 and the time stamp for three days later at the 02:00 the morning is 1367546400
Now the question:
Is there a way to extract the time duration of the double charged hours from a time frame? If so, what is the process?
Of course there is. You just need to count the interval between dates.
Let's say someone started using service since 8:00 and ended in 16:00.
Price from 8:00 - 16:00 = 2$
Price from 16:00 - 8:00 = 1$
So you need to convert the start of usage time and end of usage time to timestamp
date_default_timezone_set('UTC');
$day_start = '2011-06-22';
$day_end = '2011-06-22';
$start_usage = strtotime($day_start.' 8:00');
$end_usage = strtotime($day_end.' 17:00');
$price_low_rate = 1; //price for using service 16-8
$price_high_rate = 2; // price for using service since 8-16
$fee_for_eight_sixteen = 0; // total price for using service since 8-16
$fee_for_sixteen_eight = 0; // total price for using service 16-8
if($end_usage >strtotime($day_start.' 16:01'))
{
$fee_for_sixteen_eight = ($end_usage - strtotime($day_end.' 16:00'))/3600 * $price_low_rate;
}
if($start_usage >= strtotime($day_start.' 8:00'))
{
$fee_for_eight_sixteen = (strtotime($day_end.' 16:00') - $start_usage)/3600 * $price_high_rate;
}
echo $fee_for_eight_sixteen.' - '.$fee_for_sixteen_eight;
I've tested it and it works. Hope it helps.
Haven't tested this, but I hope it gets you on the right track:
<?php
$price = 0;
$start_timestamp = 1367449200;
$end_timestamp = 1367546400;
$start_time_of_day = 1367449200 % (24*60*60); // Number of seconds from start of the day
$end_time_of_day = 1367546400 % (24*60*60); // Number of seconds from start of the day
// How much time the time period spends in the first day (in seconds)
$first_day_time = (24*60*60) - $start_time_of_day;
// How much time the time period spends in the last day (in seconds)
$last_day_time = (24*60*60) - $end_time_of_day;
$full_days_time = $end_timestamp + $last_day_time - ($start_timestamp + $first_day_time);
$full_days = round($full_days_time/(24*60*60));
// You can calculate by hand how much one full 24-hour day from 00:00 to 00:00 costs
$price += $full_days * (2*10 + 21*5 + 1*10);
// so now the difficulty is the pieces of time on the first day and the last day.
$expensive_time = 0; // Expensive time spent on the first and last day
$cheap_time = 0;
if ($start_time_of_day<2*60*60)
{
// Renting starts before 02:00
$expensive_time += 2*60*60 - $start_time_of_day;
$cheap_time += 21*60*60; // Full 21 hours of cheap time
$expensive_time += 1*60*60; // 1 hour of expensive time from 23:00 to midnight
}
elseif ($start_time_of_day<23*60*60)
{
// Renting starts after 02:00 and before 23:00
$cheap_time += 23*60*60 - $start_time_of_day;
$expensive_time += 1*60*60; // 1 hour of expensive time from 23:00 to midnight
}
else
{
// Renting starts after 23:00
$expensive_time += 24*60*60 - $start_time_of_day;
}
// !! Use a similar strategy for the $end_time_of_day here
$price += ceil($expensive_time/60/60) * 10;
$price += ceil($cheap_time/60/60) * 5;
echo $price." euro";
?>
Related
I need to find how many seconds exist between two different unix timestamps within a certain range.
For example:
Travel Start: 05:00
Site Arrival: 07:00
Standby Hours: 06:00 - 09:00
I need to find how many seconds the user is traveling and how many seconds he spends on standby.
The above result should output:
Travel = 3600 seconds (05:00 - 06:00)
Standby = 3600 seconds (06:00 - 07:00)
Another example:
Travel Start: 10:00
Site Arrival: 11:30
Standby Hours: 06:00 - 09:00
Travel = 5400 seconds (10:00 - 11:30)
Standby = 0 seconds
Example code which I do not think is correct:
if($travel_start_time >= $standby_start_time)
{
if($first_site_arrival <= $standby_end_time)
{
$travel_during_standby = max($first_site_arrival-$travel_start_time, 0);
}
elseif($first_site_arrival >= $standby_end_time)
{
$travel_during_standby = max($first_site_arrival-$standby_end_time, 0);
}
}
else
{
$travel_during_standby = max($first_site_arrival-$standby_start_time, 0);
}
I think you're asking 'How much time is common to two possibly overlapping Unix timestamp ranges ?'
From a 'Logic' point of view...
Given that your times are already converted into Unix timestamps, as T1 and T2 for travel, and S1 and S2 for standby.
Travel time is T2-T1
Standby time is S2-S1
There will be an overlap if ((S1<T2) && (S2>T1))
If there's an overlap,then the travel during standby will be (Min(T2,S2) - Max(T1,S1))
Translating the logic into PHP is fairly straightforward...
$travel_during_standby = ((($standby_start_time < $travel_end_time)&&($standby_end_time > $travel_start_time)))? (Min($travel_end_time,$standby_end_time) - Max($travel_start_time,$standby_start_time)) : 0;
An alternative blunter approach would be to blindly calculate the overlap and ignore any negative results...
$travel_during_standby = Max( (Min($travel_end_time,$standby_end_time) - Max($travel_start_time,$standby_start_time)) , 0 );
How can I calculate the nearest hours to midnight time 00:00 regardless of date in PHP. For example:
If time is 22:00 then 2 hours are required to reach 00:00
If time is 04:00 then -4 hours are the nearest to reach 00:00
Currently I have the following PHP function:
<?php
$ts1 = strtotime('00:00');
$ts2 = strtotime('04:00');
$diff = ($ts1 - $ts2) / 3600;
?>
But this won't be helpful much in the above.
If you have the php Datetime class available you can calculate the difference between two DateTimes.
$time1 = new \DateTime('00:00');
$time2 = new \DateTime('04:00');
$diff = $time1->diff($time2, true);
$hourDifference = 0;
if ($diff->h < 12) {
$hourDifference = -$diff->h;
} elseif ($diff->h > 12) {
$hourDifference = 24 - $diff->h;
} else {
$hourDifference = 12; // kann be positive or negative
}
And you'll get a DateInverall object where you can access, hours, minuts, seconds and compare them with normal php operators.
If you'r not too interested in minutes;
1. Extract minutes.
check if minutes is > or <=30
if greater, 'store' 1
2. Extract hour
check if hour is greater than 12
if not, add 12 (store flag also to say it will be minus)
3. if greater (ref. Step 1), add 1 to extracted hour.
4. 24 - extracted hour is your interval.
Please note, this may be reduced/ simplified greatly.
Your interval (should) be correct to the nearest half hour
The answer depends on the date (not only the time). This is because of daylight saving time changes. For example might 02:59 being closer to 00:00 then 21:01 on the time where daylight saving time will set back hour.
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:
The booking starts and ends during a discount period (e.g. 3am-7am - 4 hours discounted)
The booking starts during a discount, but ends afterwards (e.g. 7am-9am - 1 hour discounted)
The booking starts and ends during a period of non-discount (10am-5pm - no discount)
The booking starts during a period of non-discount, but ends afterwards (5pm-10pm - 1 hour discounted)
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!
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.
I have a scenario in which the user selects a time and day (or multiple days) and that value must be converted to whatever that day and time would be in UTC time. I have the gmt offset amount for each user (the users set it when they signup). For instance:
A user in the eastern timezone selects:
3:15 pm, Monday, Tuesday, Friday
I need to know what time and days that information would be in UTC time. The solution has to take into situations such Monday in one timezone can be a different day in UTC time. Also, if the time can be converted to 24 hour format, that would be a plus.
For the sake of clarity, something along the lines of an array should be returned such as:
Array('<3:15 pm eastern adjusted for utc>', '<Monday adjusted for UTC>', '<Tuesday adjusted for UTC>', '<Friday adjusted for UTC>');
I don't need the result to be directly formatted into an array like that - that's just the end goal.
I am guessing it involves using strtotime, but I just can't quite my finger out how to go about it.
$timestamp = strtotime($input_time) + 3600*$time_adjustment;
The result will be a timestamp, here's an example:
$input_time = "3:15PM 14th March";
$time_adjustment = +3;
$timestamp = strtotime($input_time) + 3600*$time_adjustment;
echo date("H:i:s l jS F", $timestamp);
// 16:15:00 Monday 14th March
EDIT: kept forgetting little things, that should be working perfectly now.
Made a function to do the job:
<?
/*
* The function week_times() converts a a time and a set of days into an array of week times. Week times are how many seconds into the week
* the given time is. The $offset arguement is the users offset from GMT time, which will serve as the approximation to their
* offset from UTC time
*/
// If server time is not already set for UTC, uncomment the following line
//date_default_timezone_set('UTC');
function week_times($hours, $minutes, $days, $offset)
{
$timeUTC = time(); // Retrieve server time
$hours += $offset; // Add offset to user time to make it UTC time
if($hours > 24) // Time is more than than 24 hours. Increment all days by 1
{
$dayOffset = 1;
$hours -= 24; // Find out what the equivelant time would be for the next day
}
else if($hours < 0) // Time is less than 0 hours. Decrement all days by 1
{
$dayOffset = -1;
$hours += 24; // Find out what the equivelant time would be for the prior day
}
$return = Array(); // Times to return
foreach($days as $k => $v) // Iterate through each day and find out the week time
{
$days[$k] += $dayOffset;
// Ensure that day has a value from 0 - 6 (0 = Sunday, 1 = Monday, .... 6 = Saturday)
if($days[$k] > 6) { $days[$k] = 0; } else if($days[$k] < 0) { $days[$k] = 6; }
$days[$k] *= 1440; // Find out how many minutes into the week this day is
$days[$k] += ($hours*60) + $minutes; // Find out how many minutes into the day this time is
}
return $days;
}
?>
On one project, I have an internal calculation of times.
The days since the launch are simply enumerated:
2009/10/19: launch day
2009/10/20: day 1
2009/10/21: day 2
etc.
Now I would like to have a function which gives me the current day of the internal calculation of times. E.g. "day 129" on one day in 2010.
But it is important to have this accuracy:
2009/10/20 00:00:01 => day 1
2009/10/20 23:59:59 => day 1
2009/10/21 00:00:01 => day 2
I built the following function but it doesn't have that accuracy. Why not? Can you improve it?
function date2daycount($timestamp) {
$launchDay = 1255903200-3600*24; // launch (2009/10/19 00:00:00)
$difference = floor(($timestamp-$launchDay)/86400); // days after launch
return $difference;
}
Thanks in advance!
function date2daycount($timestamp) {
$launchDay = strtotime('19 October 2009'); // launch (2009/10/19 00:00:00)
$difference = floor(($timestamp-$launchDay)/86400); // days after launch
return $difference+1;
}