0

I am doing a booking page for house renting.

I have a datepicker were my users submits a UNIX datetime: Arrival and Departure date.
On mySQL I have a house with different seasons with "season_start" date (YYYY-mm-dd), "season_end" date & "price per day".

$seasons_select="SELECT id,season_start,season_end,daily_price FROM ".T_ITEM_SEASONS." WHERE id_item=".ID_ITEM." ORDER BY season_start ";
$res_seasons=mysql_query($seasons_select) or die("Error getting states");
$arrival_date = date('d-m-Y', $arrival_date);
$departure_date = date('d-m-Y', $departure_date);
 while ($seasons_row=mysql_fetch_assoc($res_seasons)){
  $start_date = date('d-m-Y', strtotime($seasons_row["season_start"]));
  $end_date = date('d-m-Y', strtotime($seasons_row["season_end"]));
  $current_date = $start_date;
  while($current_date != $end_date){
   $current_date = date("d-m-Y", strtotime("+1 day", strtotime($current_date)));
   $match_date = $arrival_date;
   while($match_date != $departure_date){
    $match_date = date("d-m-Y", strtotime("+1 day", strtotime($match_date)));
    if ($current_date==$match_date){ 
     echo $current_date.' This is one of the days! <br />';
    }       
   }    
  } 
 }

What is the best way to match if a date inside the user arrival/departure period is inside one or severall seasons?

My code kind of works...
I get the answer I want but after it a "Fatal error: Maximum execution time of 30 seconds exceeded in"

Sergio
  • 28,539
  • 11
  • 85
  • 132
  • http://stackoverflow.com/questions/325933/determine-whether-two-date-ranges-overlap – Salman A May 04 '13 at 19:24
  • @SalmanA, this question is not as simple as the one you refer. Although I learned by it (thank you for pointing), in my case I have 1 date range I have to cross with x different. One Arrival and Departure date can span thru low-,mid-, and/or high season, for example. – Sergio May 04 '13 at 22:11
  • [**Please, don't use `mysql_*` functions in new code**](http://bit.ly/phpmsql). They are no longer maintained [and are officially deprecated](https://wiki.php.net/rfc/mysql_deprecation). See the [**red box**](http://j.mp/Te9zIL)? Learn about [*prepared statements*](http://j.mp/T9hLWi) instead, and use [PDO](http://php.net/pdo) or [MySQLi](http://php.net/mysqli) - [this article](http://j.mp/QEx8IB) will help you decide which. If you choose PDO, [here is a good tutorial](http://j.mp/PoWehJ). – tereško May 08 '13 at 09:48

2 Answers2

1

What is the best way to match if a date inside the user arrival/departure period days inside one or severall seasons?

Well, yours looks kinda terrible :-)

I would say, let MySQL do the work – select only those records you want in the first place.

To check if a single date is within a “season”, you have to check if it is greater-equal than the season begin and lesser-equal than the season end.

To get all seasons which any day of the arrival/departure period falls into, you have to check four cases:

(| be the season start and end, and A is the select arrival and D the departure date.)

S: -------------------|-----------------|------------------
1. ---------------A--------------------------D-------------
2. ---------------A-----------------D----------------------
3. -----------------------A---------D----------------------
4. -----------------------A------------------D-------------
  1. Season falls into selected period completely.

  2. Arrival is before season start, departure before end.

  3. Arrival is after season start, departure before end.

  4. Arrival is after season start, and departure after season end.

(Before and after always meant including, so really before/on and on/after.)


Put inside a query, that could look something like this, with 2013-05-04 as arrival and 2013-07-04 as departure date:

SELECT id, season_start, season_end, daily_price FROM table
WHERE id_item = 1234 AND (
   ('2013-05-04' <= season_start AND '2013-07-04' >= season_end) OR
   ('2013-05-04' <= season_start AND '2013-07-04' <= season_end) OR
   ('2013-05-04' >= season_start AND '2013-07-04' <= season_end) OR
   ('2013-05-04' >= season_start AND '2013-07-04' >= season_end)
)
ORDER BY season_start

Since you said you receive the user input as Unix timestamps, you can either format those with PHP’s date() before inserting them into the query, or you could use MySQL’s FROM_UNIXTIME(123456789, '%Y-%M-%D') in those places instead.

And you should create an index (if not already in place) on the columns season_start and season_end (one index each), for better performance.


Edit: As is pointed out in this answer Salman referred to in comments, two conditions (and a little more creativity in applying boolean logic that I had) are enough to check, so the WHERE clause can be simplified as

WHERE id_item = 1234 AND
  ('2013-05-04' <= season_end) and ('2013-07-04' >= season_start)
Community
  • 1
  • 1
CBroe
  • 91,630
  • 14
  • 92
  • 150
  • Actually, this could be done with _two_ `<` / `>` checks. – Salman A May 04 '13 at 19:25
  • You should get _all_ the seasons with this query (using the simplified version too), in that either arrival or departure date fall into, or that are “surrounded” by arrival and departure – isn’t that what you wanted? – CBroe May 04 '13 at 22:19
  • Yes, I want all the seasons that are related to that date, but I don't understan how the `AND` will do that. Is it 8 `AND` parameters or 4? Does multiple `AND` pair together so the first is pair is prioritated and so on? Don't I need an `OR`? I am trying to make it work in my site now. (i get actually inspired to have people giving nice input, thanks!) – Sergio May 04 '13 at 22:44
  • Aah … yes, of course OR instead of AND, sorry. Edited my answer. – CBroe May 04 '13 at 22:48
  • Yes! thank you! I noticed now the extra `()` after the first `AND`. Great input! – Sergio May 04 '13 at 23:20
  • CBroe, one thing was missing, I had to add a third parameter to line 2 ('".$arrival_date."' <= season_start AND '".$departure_date."' <= season_end AND '".$departure_date."' >= season_start) OR and `('".$arrival_date."' >= season_start AND '".$departure_date."' >= season_end AND '".$arrival_date."' <= season_end)`line 4. Otherwise they would get dates from before/after the interval I needed. Thank you again for sharing your knowledge about this! – Sergio May 05 '13 at 06:47
0

Instead of looping through all days of a season to see whether a given date is within it's bounds, rather try your query as follows.

"SELECT id,season_start,season_end,daily_price FROM ".T_ITEM_SEASONS." WHERE id_item=".ID_ITEM." AND season_start <= $arrival_date AND season_end >= $departure_date ORDER BY season_start ";

where $arrival_date and $departure_date are the values from your datepickers.

This way you won't have to loop through all the days of the season to find matching dates.

A point to note - Consider the desired result in cases where the arrival and departure dates cross over seasons (arriving in one season and leaving in another) The query as above will only return rows where the arrival and departure dates fall within the same season.

Istari
  • 3,843
  • 3
  • 24
  • 21
  • Not complete enough. Does not cover all cases. E.g. when arrival is before season start but departure is between season start and end. – Salman A May 04 '13 at 19:33
  • Hence my comment at the end. The original request did not make clear what the desired behaviour is in the case of dates that span across seasons. Rather than assume that such cases should be included, I opted to ask the user to consider what the correct behaviour should be. The OP should update the question with that information to help clarify – Istari May 04 '13 at 20:18
  • Thank you Istari for your idea. As @SalmanA commented the case which I don't know how to do is when arrival and departure are not inside the same season. – Sergio May 04 '13 at 22:14