rich_traff Posted June 16, 2011 Share Posted June 16, 2011 Hi, can anyone tell me whats wrong with this code? i have an array of arrays that contain start and end dates of bookings as shown here taken from mysql; Array ( [0] => Array ( [0] => 2011-05-26 [1] => 2011-05-28 ) [1] => Array ( [0] => 2011-05-28 [1] => 2011-05-30 ) [2] => Array ( [0] => 2011-06-13 [1] => 2011-06-24 ) ) ie; booking 1: start = 2011-05-26, end = 2011-05-28 booking 2: start = 2011-05-28, end = 2011-05-30 booking 3: start = 2011-06-13, end = 2011-06-24 i then have a new start_date and end_date and i need to check that none of the dates from the array fall between the 2 new dates, new dates being unix timestamp. $start_date // unix timestamp $end_date // unix timestamp $checkDates // array (as above) $dateUnavailable = 0; foreach( $checkDates as $key => $date) { if (strtotime($date) > $start_date && strtotime($date) < $end_date); { $dateUnavailable = 1; } } no matter what dates are used, $dateUnavailable is always set to 1... Can anyone tell me what im doing wrong here or suggest a better solution that works? Quote Link to comment https://forums.phpfreaks.com/topic/239558-check-dates-from-array-dont-fall-between-2-new-dates-code-not-working/ Share on other sites More sharing options...
Psycho Posted June 16, 2011 Share Posted June 16, 2011 I see a couple of problems. First, since you have a multidimensional array, in your foreach() loop the '$date' value is an array. So, you are trying to compare an array against the start/end dates. You need to compare the two date value in the '$date' array against the start/end dates. Second, your logic of comparing the dates will not work. You can't compare the two dates individually against both the start and end dates. The logic you have will always show that there is a conflict unless the dates of the record exactly equal the start/end target dates. And, I think that should be considered a conflict as well. Think about it for a moment. If you have a start/end dates of Feb 1 to Feb 28. If you have a record for Jan1 to Jan 31, both the dates are less than the end target date, which would not be a conflict, but the logic above would make it seem so. This should be what you want. It may seem counter intuitive since you are comparing the record start date with the target end date and the record end date against the target start date. But, trust me it is correct. It will validate that the record time period does not overlap the time period of the target. $dateUnavailable = false; foreach( $checkDates as $key => $dates) { //Create variables for rrecord start/end dates list($recStart, $recEnd) = $dates; if (strtotime($recStart) < $end_date && strtotime($recEnd) < $start_date); { $dateUnavailable = true; break; } } Quote Link to comment https://forums.phpfreaks.com/topic/239558-check-dates-from-array-dont-fall-between-2-new-dates-code-not-working/#findComment-1230604 Share on other sites More sharing options...
rich_traff Posted June 17, 2011 Author Share Posted June 17, 2011 Hi, im afraid that hasn't solved the problem, $dateUnavailable is still being set to true no matter what… Firstly First, since you have a multidimensional array, in your foreach() loop the '$date' value is an array. So, you are trying to compare an array against the start/end dates. You need to compare the two date value in the '$date' array against the start/end dates. Thanks for pointing that out If you have a start/end dates of Feb 1 to Feb 28. If you have a record for Jan1 to Jan 31, both the dates are less than the end target date, which would not be a conflict, but the logic above would make it seem so. Im not sure i follow here… Both record dates are less than the target end date, but neither of them are greater than the target start date so surely the if statement in my original code would not be true if (strtotime($recStart) < $end_date && strtotime($recEnd) < $start_date); Sorry but i don't think this is correct as it would not stop someone selecting new dates that fall either side of the record dates… Perhaps i've not been very clear in my original post, to reiterate the problem… I have a calendar that lets a user book out cars by selecting a start and end date for the booking. It currently shows all the days the car is already booked out on and will not let you select those days. There is nothing to stop someone selecting a start date before one booking and an end date after it though which would go through another booking, which is what i need to stop happening. ie - there is a booking for the 7th-8th, i need to stop someone selecting the 6th and 9th as start/end dates and creating a booking that overlaps the first... Quote Link to comment https://forums.phpfreaks.com/topic/239558-check-dates-from-array-dont-fall-between-2-new-dates-code-not-working/#findComment-1230939 Share on other sites More sharing options...
Psycho Posted June 17, 2011 Share Posted June 17, 2011 The logic of the code I provided is valid. But, I think I misunderstood which dates were which. If the dates in the $checkDates array are the already booked dates and the $start_date & $end_date are the proposed dates for a new booking, then you just need to reverse the logic in the code. $dateUnavailable = false; foreach($checkDates as $key => $dates) { //Create variables for rrecord start/end dates list($bookedStart, $bookedEnd) = $dates; if ($start_date < strtotime($bookedEnd) && $end_date > strtotime($bookedStart)); { $dateUnavailable = true; break; } } If you still get invalid results provide the start/end dates and the $checkDates array. As a visual example, below are the various combinations of how a booked date range and various requested date ranges. If you look at all the "invalid" date ranges (the requested start date is before the booked end date) AND (the requested end date is before the booked start date) 3-----6 <== Booked Date Range ---------------- <== Valid Request date ranges 1-2 1---3 6---8 7-8 ---------------- <== Invalid Request date ranges 2---4 3-4 4-5 5-6 5---7 2---------7 Quote Link to comment https://forums.phpfreaks.com/topic/239558-check-dates-from-array-dont-fall-between-2-new-dates-code-not-working/#findComment-1231114 Share on other sites More sharing options...
rich_traff Posted June 20, 2011 Author Share Posted June 20, 2011 apologies if i wasn't clear which dates were which. Im still getting invalid results though... I've been checking through the rest of my code to make sure there are no errors before getting to this point and cant find any... Here is a working example of the dates; Array of already booked dates: Array ( [0] => Array ( [0] => 07/20/2011 [1] => 07/21/2011 ) [1] => Array ( [0] => 08/16/2011 [1] => 08/17/2011 ) ) dates selected by user: start date: 1312844400, end date: 1312930800 // ok - should set $dateUnavailable to false start date: 1313362800, end date: 1313622000 // not aloud - should set $dateUnavailable to true currently, all date entries are resulting in $dateUnavailable being set to true Quote Link to comment https://forums.phpfreaks.com/topic/239558-check-dates-from-array-dont-fall-between-2-new-dates-code-not-working/#findComment-1232117 Share on other sites More sharing options...
Psycho Posted June 20, 2011 Share Posted June 20, 2011 OK, I have been "assuming" that the array you are posting is not formatted as it REALLY is. You should do a print_r() and post the result of that. Here is what I assume is the true format of your array: Array ( [0] => array( [0] => 07/20/2011 [1] => 07/21/2011 ) [1] => Array ( [0] => 08/16/2011 [1] => 08/17/2011 ) ) Also, as my signature states I do not always test the code. If I am confident in the logic I leave it to the person I am providing the code for to do any debugging of syntax errors. In this case, the error did not produce a code failure. There was an errant semi-colon at the end of the IF statement. During my debugging I transformed the script into a function. The revised "tested" code is below. However, if the booked dates are coming from a database you should just do a single query against the database to see if there is a conflict rather than querying the database for all the records and then checking the requested dates. I would have to know the format of the data in the database to provide a query. Revised script //Returns true/false based upon whether the requested dates conflict //with the already booked dates in the $bookedDates array function datesAvailable($bookedDates, $start_date, $end_date) { $datesAvailable = true; foreach($bookedDates as $key => $dates) { //Create variables for rrecord start/end dates list($bookedStart, $bookedEnd) = $dates; if ($start_date < strtotime($bookedEnd) && $end_date > strtotime($bookedStart)) { return false; } } return true; } //Array of already booked dates $checkDates = array( array ('07/20/2011', '07/21/2011'), array ('08/16/2011', '08/17/2011') ); $available = datesAvailable($checkDates, 1312844400, 1312930800); //returns true $available = datesAvailable($checkDates, 1313362800, 1313622000; //returns false Quote Link to comment https://forums.phpfreaks.com/topic/239558-check-dates-from-array-dont-fall-between-2-new-dates-code-not-working/#findComment-1232309 Share on other sites More sharing options...
TeNDoLLA Posted June 20, 2011 Share Posted June 20, 2011 I think best way would be to have start and end date fields in MySQL and then just use a SQL query to select the dates between or outside that pair of dates. Quote Link to comment https://forums.phpfreaks.com/topic/239558-check-dates-from-array-dont-fall-between-2-new-dates-code-not-working/#findComment-1232419 Share on other sites More sharing options...
Psycho Posted June 20, 2011 Share Posted June 20, 2011 I think best way would be to have start and end date fields in MySQL and then just use a SQL query to select the dates between or outside that pair of dates. I wish I had though of that. Oh wait, I did. However, if the booked dates are coming from a database you should just do a single query against the database to see if there is a conflict Quote Link to comment https://forums.phpfreaks.com/topic/239558-check-dates-from-array-dont-fall-between-2-new-dates-code-not-working/#findComment-1232455 Share on other sites More sharing options...
rich_traff Posted June 21, 2011 Author Share Posted June 21, 2011 @mjdamato, ok - i understand your logic now and appreciate it is sound. What i have found is there is a problem with my array itself… After doing print_r it displayed '1' and nothing else… I should have done this first as i was copying the results of the query from another function elsewhere in the script (although it is the exact same query) Even when i insert the array manually though, it still shows '1' This is the exact code i am using right now… (it is a joomla component btw) $car_id = JRequest::getInt('id', ''); /* $db->setQuery("SELECT start_date, end_date FROM #__carbooking_bookings WHERE car_id = '$car_id'"); $bookedDates = $db->loadRowList(); */ $bookedDates = array( array ('07/20/2011', '07/21/2011'), array ('08/16/2011', '08/17/2011') ); $datesUnavailable = 0; foreach($bookedDates as $key => $dates) { //Create variables for rrecord start/end dates list($bookedStart, $bookedEnd) = $dates; if ($start_date_unixTime < strtotime($bookedEnd) && $end_date_unixTime > strtotime($bookedStart)) { $datesUnavailable = 1; } } if ($datesUnavailable = 1) { $this->setRedirect(JRoute::_('index.php?option=com_carbooking&id=' . $row->id . '&view=single'), 'Your selection falls over another booking, dates Unavailable: ' . $datesUnavailable . ', start date: ' . $start_date_unixTime . ', end date: ' . $end_date_unixTime . ', array: ' . print_r($bookedDates) . ', car id: ' . $car_id); } The message displayed on redirect ie from this $this->setRedirect(JRoute::_('index.php?option=com_carbooking&id=' . $row->id . '&view=single'), 'Your selection falls over another booking, dates Unavailable: ' . $datesUnavailable . ', start date: ' . $start_date_unixTime . ', end date: ' . $end_date_unixTime . ', array: ' . print_r($bookedDates) . ', car id: ' . $car_id) gives exactly this; Your selection falls over another booking, dates Unavailable: 1, start date: 1312844400, end date: 1312930800, array: 1, car id: 1 Showing $datesUnavailable is being set to 1 the start and end dates are formatted correctly the array however, instead of being this; Array ( [0] => Array ( [0] => 07/20/2011 [1] => 07/21/2011 ) [1] => Array ( [0] => 08/16/2011 [1] => 08/17/2011 ) ) is this; 1 do you know why this might be happening? Quote Link to comment https://forums.phpfreaks.com/topic/239558-check-dates-from-array-dont-fall-between-2-new-dates-code-not-working/#findComment-1232704 Share on other sites More sharing options...
rich_traff Posted June 21, 2011 Author Share Posted June 21, 2011 OK, I have been "assuming" that the array you are posting is not formatted as it REALLY is. You should do a print_r() and post the result of that. Here is what I assume is the true format of your array: Yes, you were correct in your assumption... at least you were correct in assuming that i assumed the array would be formatted that way... turns out i should have checked more thoroughly... Quote Link to comment https://forums.phpfreaks.com/topic/239558-check-dates-from-array-dont-fall-between-2-new-dates-code-not-working/#findComment-1232708 Share on other sites More sharing options...
Psycho Posted June 21, 2011 Share Posted June 21, 2011 You can't do a print_() inside an echo statement (I have made the same mistake before). You would have to assign the results of a print_r to a variable then echo out the variable. Since I did test the last code I provided, I am going to suggest you use that code. Also, it is more logical. Having a variable called $datesUnavailable and setting it to false to mean that dates are available is the programmatical equivalent of a double negative. It can be confusing. That is why I had changed the logic to determine in "datesavailable" is true. Below is a rewrite of your script above with my latest function incorporated with LOTS of debugging code to help pinpoint any issues if the results are not what you expect. As you have done previously, the script currently has a hard-coded $bookedDates array defined in the datesAvailable() function. Once that works, you can remove the hard-coded array and uncomment the query to get the booked dates from the DB. I modified the function to take a parameter for the card ID and to run the query for booked dates in the function. If I didn't make any errors it should work once you uncomment the line to run the query. <?php //Returns true/false based upon whether the requested dates conflict //with the already booked dates in the DB for the requested car id function datesAvailable($car_id, $start_date_ts, $end_date_ts) { /* $query = "SELECT start_date, end_date FROM #__carbooking_bookings WHERE car_id = '$car_id'"; $db->setQuery($query); $bookedDates = $db->loadRowList(); */ //Hard coded test array $bookedDates = array( array ('07/20/2011', '07/21/2011'), array ('08/16/2011', '08/17/2011') ); #DEBUG echo "Booked dates array contains " . count($bookedDates) . " records<br><br>\n"; echo "Checking availabliity from " . date('m-d-Y', $start_date_ts) . " to " . date('m-d-Y', $end_date_ts) . "<br><br>\n"; foreach($bookedDates as $key => $dates) { #DEBUG echo "Checking booked dates of {$dates[0]} to {$dates[0]} - "; //Create variables for rrecord start/end dates list($bookedStart, $bookedEnd) = $dates; if ($start_date_ts < strtotime($bookedEnd) && $end_date_ts > strtotime($bookedStart)) { //Conflicts detected, return false #DEBUG echo "CONFLICT, Return FALSE<br>\n"; return false; } } #DEBUG echo "No Conflicts, Return TRUE<br>\n"; //No conflicts detected, return true return true; } //End function datesAvailable() $car_id = JRequest::getInt('id', ''); if (!datesAvailable($car_id, $start_date_unixTime, $end_date_unixTime)) { $redir_url = 'index.php?option=com_carbooking&id=' . $row->id . '&view=single'; $redir_msg = "Your selection falls over another booking, dates Unavailable: start date: {$start_date_unixTime}, end date: {$end_date_unixTime}, car id: {$car_id}"; $this->setRedirect(JRoute::_($redir_ur), $redir_msg); } ?> Quote Link to comment https://forums.phpfreaks.com/topic/239558-check-dates-from-array-dont-fall-between-2-new-dates-code-not-working/#findComment-1232840 Share on other sites More sharing options...
rich_traff Posted June 22, 2011 Author Share Posted June 22, 2011 ok, i think this is nearly there but have another issue which i think is just due to my inexperience using functions and not really knowing how to use them together properly… this code needs to be part of a larger function that checks a few things before returning a final output. I've taken the last rewritten function you provided and tested it on its own and it works no problems (the debugging helped me understand more so thanks for that) Im not really sure how to include functions within other functions though (and got errors whilst trying) so used an include. When i remove the redirects (from the controller file) your code echo's out everything you expect it to, correct date, returns true or false correctly etc. When i try to take the return value and base an if statement on it though (in the controller) it is always set to true… This is the controller file function <?php function points_spend() { // does stuff here $car_id = JRequest::getInt('id', ''); include 'bookings_overlap.php'; if ( $datesAvailable = true) { $this->setRedirect(JRoute::_('index.php?option=com_carbooking&id=' . $row->id . '&view=single'), 'The dates are true' . $datesAvailable); } elseif ( $datesAvailable = false) { $this->setRedirect(JRoute::_('index.php?option=com_carbooking&id=' . $row->id . '&view=single'), 'The dates are false' . $datesAvailable); } // does more stuff here } ?> and the included file <?php //Returns true/false based upon whether the requested dates conflict //with the already booked dates in the DB for the requested car id function datesAvailable($car_id, $start_date_unixTime, $end_date_unixTime) { /* $query = "SELECT start_date, end_date FROM #__carbooking_bookings WHERE car_id = '$car_id'"; $db->setQuery($query); $bookedDates = $db->loadRowList(); */ //Hard coded test array $bookedDates = array( array ('07/20/2011', '07/21/2011'), array ('08/16/2011', '08/17/2011') ); foreach($bookedDates as $key => $dates) { list($bookedStart, $bookedEnd) = $dates; if ($start_date_unixTime < strtotime($bookedEnd) && $end_date_unixTime > strtotime($bookedStart)) { //Conflicts detected, return false return false; } } //No conflicts detected, return true return true; } $datesAvailable = datesAvailable($car_id, $start_date_unixTime, $end_date_unixTime); ?> Can you tell me where im still going wrong with this? btw - i fully appreciate your time spent on this, i know i've already asked a lot... Quote Link to comment https://forums.phpfreaks.com/topic/239558-check-dates-from-array-dont-fall-between-2-new-dates-code-not-working/#findComment-1233380 Share on other sites More sharing options...
kenrbnsn Posted June 22, 2011 Share Posted June 22, 2011 Actually, you can use print_r inside an echo. Like this: <?php echo '<pre>' .print_r($array, true) . '</pre>'; ?> You can do something similar in the mail function <?php mail($to,$subject,print_r($array,true),$headers); ?> Ken Quote Link to comment https://forums.phpfreaks.com/topic/239558-check-dates-from-array-dont-fall-between-2-new-dates-code-not-working/#findComment-1233391 Share on other sites More sharing options...
Psycho Posted June 22, 2011 Share Posted June 22, 2011 @rich_traff Kinda difficult to debug your problem without seeing it all together, but I'll give it a go. In your controller "function" you have an if() condition as follows: if ( $datesAvailable = true) First off, if the value of $datesAvailable will be true or false, you don't need "test" if it is equal to true. That is redundant. Just use if ( $datesAvailable) But, the problems with what you have is 1) You are ASSIGNING the value of true to the variable $datesAvailable not testing it (which would be corrected by what I posted just above). 2) I don't see where you ever assigned a value to $datesAvailable before that if() condition is run. Variables created outside a function are not available inside a function. It is called variable scope. You can code around this, but it is bad practice. What I thin you should be doing is simply calling the datesAvailable() function INSIDE the if() statement. But, to do so you need to pass the required parameters. I only see the car_id defined in the function; you also need the start/end dates. Example: if ( datesAvailable($car_id, $startDate, $endDate)) So, you would need to pass the start/end dates to the function you have. Alternatively, you could define the $datesAvailable outside the function and then pass that to your function. Quote Link to comment https://forums.phpfreaks.com/topic/239558-check-dates-from-array-dont-fall-between-2-new-dates-code-not-working/#findComment-1233486 Share on other sites More sharing options...
rich_traff Posted June 23, 2011 Author Share Posted June 23, 2011 @mjdamato, thanks so much for your help on this setting the if statement to this corrected the problem if ( datesAvailable($car_id, $start_date_unixTime, $end_date_unixTime)) Now, theres just one other thing, if you would be so kind... You mentioned the most efficient solution would be to check for a conflict in the db with the query itself, how would i go about that? Quote Link to comment https://forums.phpfreaks.com/topic/239558-check-dates-from-array-dont-fall-between-2-new-dates-code-not-working/#findComment-1233799 Share on other sites More sharing options...
Psycho Posted June 23, 2011 Share Posted June 23, 2011 You mentioned the most efficient solution would be to check for a conflict in the db with the query itself, how would i go about that? Seriously? After all this work you now want to change the solution? I'm not going to write any code, but I'll give you some info to do it yourself: Instead of querying for ALL the records for the specified car ID, you would instead do a query for ONLY the records that conflict with the requested dates. Then check how many records were returned using mysql_num_rows(). If 0, there are no conflicts, if there are 1 or more, then there are conflicts. That way you don't need to process the DB results, just check how many results were returned. You will need to format the dates appropriately, but the query would look something like this. SELECT start_date FROM #__carbooking_bookings WHERE car_id = '$car_id' AND end_date > $requested_start_date AND start_date < $requested_end_date LIMIT 1 Quote Link to comment https://forums.phpfreaks.com/topic/239558-check-dates-from-array-dont-fall-between-2-new-dates-code-not-working/#findComment-1233835 Share on other sites More sharing options...
rich_traff Posted June 23, 2011 Author Share Posted June 23, 2011 Seriously? After all this work you now want to change the solution? Apologies… i didn't think that through before making my last post. I had in my head it would just be the query that would change, but the function would remain, clearly not so… You've given me more than enough help on this though and i really do appreciate it! Quote Link to comment https://forums.phpfreaks.com/topic/239558-check-dates-from-array-dont-fall-between-2-new-dates-code-not-working/#findComment-1233843 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.