This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Determine Whether Two Date Ranges Overlap
I am trying to work out if two time ranges in PHP overlap. I've been referring to Determine Whether Two Date Ranges Overlap for my initial try, however, it's not matching all cases. If a time range is nested in between the start and end times of another time range, it's not being matched. If it overlaps the beginning or the end of the shift, or if the shifts are exact matches, it works as expected.
Check out this image of what I'm talking about:
Basically, I am trying to hide any orange shifts if they overlap any red shifts anywhere. Here's the relevant portion of code I'm trying to use to make this happen.
if(($red['start'] <= $orange['end']) && ($red['end'] >= $orange['start'])) {
//Conflict handling
}
The values of the variables are UNIX timestamps. Working through the numbers logically, I understand why the statement above fails. There are obviously ways I could do more logic to determine if the one shift falls in the other shift (which is what I may need to do), but I was hoping for a more universal catch.
EDIT: Adding the values of each block's start and end time. I agree what I have should work. The fact that it isn't is where my issue lies. I'm probably overlooking something dumb.
orange-start = 1352899800
orange-end = 1352907000
red-start = 1352923200
red-end = 1352926200
Therefore my logic would state:
if((1352923200 <= 1352907000) && (1352926200 >= 1352899800))
So following that, the first comparison fails.
EDIT 2: It looks like my logic is sound (which I thought was the case), and my issue is something related to the UNIX timestamp not matching the actual time being displayed. I thank those who worked though this with me and help me discover that as being the issue. I wish I could accept both Andrey's and Jason's answers.
If you have two ranges [b1, e1] and [b2, e2] (where it is already established that b1 < e1 and b2 < e2) then the overlap is detected by the following logical expression
not (e2 < b1 or e1 < b2)
which can be rewritten as
e2 >= b1 and e1 >= b2
In your syntax that would be
if(($orange['end'] >= $red['start']) && ($red['end'] >= $orange['start'])) {
//Conflict handling
}
I.e. you got it correctly. Why you are claiming "Working through the numbers logically, I understand why the statement above fails." is not clear to me. What exactly fails? (And I don't know why is everyone coming up with ridiculously "overengineered" checks, with more than two comparisons.)
Of course, you have to decide whether touching ranges are considered overlapping and adjust the strictness of the comparisons accordingly.
P.S. The sample ranges you provided in your edit do not overlap, and your comparison correctly recognizes it as no-conflict situation. I.e. everything works as it should. Where do you see the problem?
The logic is correct. The timestamps you provided for $red (8-8:50pm) and $orange (1:30-3:30pm) do not overlap.
Given correct values (that reflect your screenshot), the overlap is indeed found:
function show_date($value, $key) {
echo $key, ': ', date('r', $value), PHP_EOL;
}
$red = array('start' => strtotime('today, 2pm'), 'end' => strtotime('today, 2:45pm'));
$orange = array('start' => strtotime('today, 1:30pm'), 'end' => strtotime('today, 4pm'));
array_walk($red, 'show_date');
array_walk($orange, 'show_date');
if (($red['start'] <= $orange['end']) && ($red['end'] >= $orange['start'])) {
echo 'Conflict handling';
}
My guess would be you have a timezone conversion issue.
You need to check if the you have a "RED" task which starts OR ends between the start and the end of an "ORANGE" task. Like this you should detect every "ORANGE" task overlapping a "RED" task.
if((($red['start'] <= $orange['end']) && ($red['start'] >= $orange['start'])) ||
(($red['end'] <= $orange['end']) && ($red['end'] >= $orange['start'])) ) {
//Conflict handling
}
EDIT: as stated by AndreyT this is kind of overkill and you can do better with less check
if ((($red['start'] <= $orange['end']) && ($red['start'] >= $orange['start']))
|| (($red['end'] <= $orange['end']) && ($red['end'] >= $orange['start']))
|| (($red['start'] >= $orange['start']) && ($red['end'] >= $orange['end']))
) {
// conflict happens if Red starts sometime between Orange start and end
// or if Red ends sometime between Orange start and end
// or if Red starts before Orange starts and ends after Orange ends
}
Related
I think I have a relatively simple question, I just think I'm misunderstanding an aspect of it.
I have an index page where in one of the table cells I have an if statement:
#if (Carbon\Carbon::parse($shipment->due_date)->diffInDays(false) > 0 && Carbon\Carbon::parse($shipment->due_date)->diffInDays(false) < 10)
Where the falses are is where I would like to declare that if the day is in the future, say like tomorrow compared to today, I will have a -1 returned, whereas if I refer to yesterday, I will have a 1 returned.
The problem is I am trying to use the docs but they are lining up for me no matter what sort of way I try them: http://carbon.nesbot.com/docs/#api-humandiff
However I should mention that on the same layout I can do this:
{{Carbon\Carbon::parse($shipment->due_date)->diffInDays()}}
and return the number of days in the past or future (even though both are positive) so I know the above works (in a way, but I still need the positive or negative mentioned).
You need to provide a Carbon date as the first parameter for diffInDays(). So, the logic will be:
Carbon\Carbon::parse($shipment->due_date)->diffInDays(now(), false)
Or:
now()->diffInDays(Carbon\Carbon::parse($shipment->due_date), false)
Depending on what exactly you're trying to achieve.
false as the second parameter makes the method return signed value (positive or negative).
You can use:
Carbon\Carbon::parse($shipment->due_date)->diffInDays(null, false)
in place of
Carbon\Carbon::parse($shipment->due_date)->diffInDays(false)
This is becuase method signature looks like this:
public function diffInDays(Carbon $dt = null, $abs = true)
{
$dt = $dt ?: static::now($this->getTimezone());
return (int) $this->diff($dt, $abs)->format('%r%a');
}
In addition looking at your logic I think it's too complicated. I think it would be enough to use:
#if (Carbon\Carbon::parse($shipment->due_date)->diffInDays(null, false) < 10)
the first condition is not necessary I believe
Also in case you are using Laravel 5.5 you should rather use:
Illuminate\Support\Carbon
instead of
Carbon\Carbon
in case you wanted to add some custom methods to this class.
I'm not very skilled when it comes to PHP but I've created this and it's probably not the best way to put it together but the only one that came to my mind right now.
What are we looking at?
It's the Apple Watch 'standing up in each hour' activity ring. This ring holds 12 image slices so called 'steps' because you have to stand up at least 12 times a day till you reach your goal (100% full circle) this means when you stand for 14 or 16 times a day the ring will loop further around 100% but the only difference between slide 2 and 14 is the background behind the circle will already be filled.
Because I don't like to create 24 slices but only 12, I will rotate slide number 12 (full circle) X degree when the value gets over 12+ this will keep the amount of used images on the page low because we keep using slide number 12 most of the time only rotate it around for step 12 till 24.
Example: the blue middle ring
PHP wise everything is working so far but you can imagine how tall those if else list will become when I start the red 'move' or calories burned circle. This circle has 100 slices or better called steps. The green circle has 30 slices.
That's why I was wondering if there is maybe a more lean way to make those if else steps. Maybe performance wise this can be done a lot better.
Thanks already..
This looks like a simple math problem. Without looking at all the details and making it even shorter (there is probably no need for an if statement at all...), you can already see that:
if ($stand > 12) {
$stanr = ($stand % 12) * 30;
$stand = 12;
}
Erm...
$stanr = 0;
if ($stand <= 12) {
} elseif (($stand > 12) and ($stand < 24) {
$stanr = ($stand - 12) * 30;
$stand = 12;
else {
$stand = 0;
}
Any idea of what would be the best way of writing a function in PHP for an online registration system with possibility of objects' occupancy;
Just to be clear:
I want to check the availability of one object in the database by writing a function and by comparing two variables:
Starting time of reservations;
Their duration (finishing time);
So when a new reservation is entered I check the database; if it doesn't pass the limit of objects in that period (by comparing to previous reservations) it gives a message which I will then pass it to JavaScript and enable the Submission button; but if it passes the limit in my JavaScript I'll suggest a duration which is available for the entered Starting Time;
In my current PHP function I am having some problems:
First I am using so many variables and so many loops (which may cause the system slow if it gets bigger) and the code seems quite messy!
It doesn't recognize the difference between serial or concurrent reservations therefore it behaves the same to these reservations.
Here is a snippet of my function:
$reservation = new Reservation;
$reservations = $reservation -> fetch_all();
foreach ($reservations as $reservation) {
for ($j = $res_code['res_code_st']; $j < $res_code['res_code_fi']; $j++) {
for ($i = $reservation['res_code_st']; $i < $reservation['res_code_fi']; $i++) {
if ($i == $j) {
$count = $count + 1;
$arr[] = $reservation['res_code_st'];
$arr[] = $reservation['res_code_fi'];
break 2;
Which actually I'm storing time in this format;
For example for 12:30 I'm storing 1230 or for 09:20 I'm storing 0920 and then I'm checking every minute of any item with every minute of new reservation (everything happens in the same day: Days don't matter!) and in case it finds a match I count it as a new reservation in that period (the reason why it doesn't differ concurrency and serial);
I believe it should be simple but I'm kinda confused and my mind doesn't work for a better solution right now!
Thanks for your times :)
EDIT
I tried the suggested way of #kamil-maraz , I think it saves some time for reducing complexity but I still couldn't figure out how to check the concurrency.
Let me give one example:
There are four possibility of disturbance I try to show in this symbolic figure,
Suppose each line is a reservation across time, first line is for new reservation and next four are already stored in the DB;
Four disturbance are as :
One that starts before and ends at the middle of new request,
One that starts before and ends after the new request;
One that is completely inside the new reservation;
One that starts after the new request and ends after it;
0-----------------0
0--------------------------------0
0--------------0
0----------0
0-----0
$result = $db -> prepare('SELECT Count(reservation_id) FROM reservations WHERE (res_code_st < ? AND res_code_fi > ?) OR (res_code_st > ? AND res_code_fi < ?) OR (res_code_st < ? AND res_code_fi > ?) OR (res_code_st < ? AND res_code_fi > ?)');
$result -> execute(array($res_code['res_code_st'], $res_code['res_code_st'], $res_code['res_code_st'], $res_code['res_code_fi'], $res_code['res_code_st'], $res_code['res_code_fi'], $res_code['res_code_fi'], $res_code['res_code_fi']));
$row = $result -> fetch();
This is giving me the number of reservations in the interval of new request; But what about this case:
0--------------------------0
0-----0
0-----0
0------0
Although in the interval there are 4 reservations which is invalid (Suppose the #object limit == 3 ), but since at each time not more than 2 reservations are made it is still valid (the concurrency problem which I was talking about).
Any idea how should I change the SQL function to fix this ?
It seems to me, that it could be done entirely on the database. You are fetching all results and then you do some magic over data. But you can do it through a database query.
for example somethging like this:
SELECT COUNT(id) FROM reservations WHERE date < ... AND date > ... AND ... etc
then, in the php, you can test count ...
if you want to test different types of reservations, concurent, etc. you can use aggregated table (Like somebedy used here and you can store in rows types of reservations too.
this question will feel silly and very basic, but i dont know why it occures and why php is not supporting it :( . So please ignore my idiotic statements in this question.
While working in ZF, i need to check an age variable with selected criteria for age ranges. I use Zend Studio as IDE. So when i placed if conditions like below:
if(20 <= $userAge <= 30) {...}
I then changed my conditions like below, which works fine:
if($userAge >= 20 AND $userAge <= 30) {...}
Zend studio did not created a syntax errors and everything seems fine, but when i reloaded my page , i got a php error
Parse error: syntax error, unexpected '<=' (T_IS_SMALLER_OR_EQUAL) in /Applications/XAMPP/xamppfiles/htdocs/othaim-jobs/application/modules/search/models/Search.php on line 240
As i remember such kind of if statements are allowed in some other languages (i think c / c++, not sure about others).
I hope i will get a nice response.
Thanks to all.
instead of
if(20 <= $userAge <= 30) {...}
why dont you use simple approach
if( $userAge>= 20 && $userAge <=30)
{}
You can rewrite your example like this
<?php
$userage=21;
if($userage >= 20 && $userage <= 30)
{
echo "Yes you are in this category !"; //prints since 21 ranges between 20 and 30
}
To check age between 20 and 30, Condition should be
if($userAge >=20 and $userAge<=30)
In PHP, is there a fastest/proper way of ordering if/else if statements? For some reason, in my head, I like to think that the first if statement should be the anticipated "most popular" met condition, followed by the 2nd, etc. But, does it really matter? Is there is a speed or processing time affected if the 2nd condition is the most popular choice (meaning the system must always read the first condition)
Ex:
if ("This is the most chosen condition" == $conditions)
{
}
else if ("This is the second most chosen condition" == $conditions)
{
}
else if ("This is the third most chosen condition" == $conditions)
{
}
Speedwise, it won't make a difference... Not a noticeable one... The order does count (it's sensibly faster putting the most used condition first), however it doesn't count for much. Choose the order which provides the best readability to those modifying and maintaining your code. They'll thank you later.
EDIT:
Also, consider this:
My function will return with a 25% chance.
I prefer writing:
if ( $chance25 )
return;
else if ( $chance40 )
doSomething();
else if ( $chance30 )
doSomethingElse();
else if ( $chance5 )
doSomethingElse2();
rather than:
if ( $chance40 )
doSomething();
else if ( $chance30 )
doSomethingElse();
else if ( $chance25 )
return;
else if ( $chance5 )
doSomethingElse2();
It's just nicer ordering by functionality...
EDIT2:
One size does not fit all. If your conditions are methods returning booleans, order them by how fast the method runs combined with the chance. I guess there's not really one good answer, you need to adapt. For example, if my $chance25 was replaced by a method reallySlowMethodDoNotUseUnlessYouReallyHaveTo(), I would surely check it last. :D
I agree with what #Luchian. Your primary focus should be readability of the code
You should profile your application before you optimize your code. How you order your condition is highly dependent on how much time is spent in "each if condition".
Let's take an example:
Execution time - %ge called
Case 1 - 50 seconds (80% of time)
Case 2 - 10 seconds (15% of time)
Case 3 - 1 second (5% of time)
100 runs:
Order A (In the order of "how often a condition is executed")
Case 1, Case 2, Case 3 = (80 * 50) + (15 * 60) + (5 * 61) = 5205 seconds
Order B (In the order of "execution times")
Case 3, Case 2, Case 1 = (5 * 1) + (15 * 11) + (80 * 61) = 5050 seconds
Your application is probably a web application (since this is most popular usage of PHP), so most of the time it waits for external resources like database, file access or webservices. Unless you're doing it in a loop that's executed thousands of times, or in a recursive method, it won't really matter which condition goes first. Strive for code that's easy to read.
depends on your preference of operation
you might want condition two to activate rather than condition one and vice versa
$value=25;
if ($value > 20)
{
$value=200;
}
else if ($value < 50)
{
$value=5;
}
If you are simply checking the value of $conditions against multiple possible text values, instead of doing if/else, use switch.
switch ($conditions) {
case "This is the most chosen condition":
// do stuff
break;
case "This is the second most chosen condition":
// do stuff
break;
case "This is the third most chosen condition":
// do stuff
break;
default:
// do stuff
}
If the most common condition is first, it will not have to evaluate any other cases and will therefore be faster, but the difference is going to be so extremely small that it really isn't going to matter one way or another. Usually you should go for readability over speed.