Welcome to WebmasterWorld Guest from 54.158.143.40

Forum Moderators: coopster & jatar k

Message Too Old, No Replies

Days between Dates

calculate days in each month between two dates

   
9:23 am on Jul 23, 2011 (gmt 0)

10+ Year Member



I need to calculate monthly occupancy levels in a simple reservation system. The MySQL database stores an arrival and a departure date in YYYY-MM-DD format. Iím tearing my hair out trying to find a simple way for PHP to work out the days for each month when the reservation crosses one or more month ends.

Take an arrival of 2011-03-25 and departure of 2011-05-03 for example. How can I calculate the results (March = 7 day; April = 30; May = 2) in a simple and efficient way?

Any help would be much appreciated.
1:36 pm on Jul 23, 2011 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Use mktime() to convert the dates into Unix timestamps, subtract one result from the other and divide by (24 * 60 * 60). Good luck!
9:31 am on Jul 24, 2011 (gmt 0)

5+ Year Member



find a simple way for PHP to work out the days for each month when the reservation crosses one or more month ends.

The simplest way is to simply loop from the timestamp of the arrival date to the timestamp of the departure date in intervals of 86400 (number of seconds in a day) being added to the timestamp of the first date, incrementing a counter for the current month and when the month should happen to change add counter for that month and work with it then. Essentially what the below monthDaysBetween function does.
Enjoy:

<?php

function monthDaysBetween($dateA, $dateB) {
$ts1 = strtotime($dateA);
$ts2 = strtotime($dateB);
$a = array();
$month = date('F', $ts1); //string name of month, such as "July"
$year = date('Y', $ts1); //four digit year
$prop = $month.' '.$year;
$a[$prop] = 0;
while ($ts1 < $ts2) {
$a[$prop]++;
$ts1 += 86400; //86400 seconds in a day
$tmpMonth = date('F', $ts1); //string name of month, such as "July"
if ($tmpMonth !== $month) { //we are in to the next month
$month = $tmpMonth;
$year = date('Y', $ts1); //four digit year
$prop = $month.' '.$year;
$a[$prop] = 0;
}
}
return $a; //array of numbers of nights stayed in particular months betweent the two dates
}

//a number of arrays of arrival and departure dates for testing:
$tests = array(
array('arrival' => '2011-03-25', 'departure' => '2011-05-03'),
array('arrival' => '2011/7/24', 'departure' => '2011/7/29'),
array('arrival' => '2011-8-27', 'departure' => '2011-9-3'),
array('arrival' => '2011-03-25', 'departure' => '2012-05-03')
);

foreach ($tests as $arr) {
$arrival = $arr['arrival'];
$departure = $arr['departure'];
$nightsStayed = monthDaysBetween($arrival, $departure);
$totalNights = array_sum($nightsStayed);
echo "<p>Arrive: $arrival, Depart: $departure<br>Total Nights: $totalNights</p>";
echo '<pre>';
print_r($nightsStayed);
echo '</pre><hr>';
}

?>

If anybody's wondering, how to post formatted code on webmasterworld [webmasterworld.com]
Do not copy formatted code on webmasterworld from IE, use other browser such as Firefox.
1:09 am on Jul 25, 2011 (gmt 0)

5+ Year Member



Oops, just revisiting this I realized I omitted one thing there. If the departure date falls on the first day of a month then that will put out for example [September 2011] => 0 which we don't want. So at the end of the monthDaysBetween function change this part:
    return $a;

to the following:
    if ($a[$prop] === 0) {
unset($a[$prop]);
}
return $a;


Also, I guess I was being a bit presumptive that a person/persons reading the example may know how to actually access the individual items in the array returned by the monthDaysBetween function. To better show how to do that, change:
    print_r($nightsStayed);

to the following:
    foreach ($nightsStayed as $monthYear => $nights) {
echo $monthYear.' : '.$nights.' nights stayed<br>';
}
10:28 am on Jul 25, 2011 (gmt 0)

10+ Year Member



Brilliant!

I had worked out a routine to achieve what I needed, but your routine is around 30% shorter. So, I shall have some fun comparing the two and hopefully learing from it. Thank you!