Here's a solution that'll accurately determine the number of months and number of days, including leap years. It assumes that things like July 21 to August 21 is 1 month 0 days, not 1 month 1 day, and that March 21 to April 20 is 0 months 30 days, not 1 month 0 days. The latter in both cases is what occurs when you just do a straight divide by 30 to calculate months.
I'm sure there's a better way to optimize the function, but it gets the job done:
function diff_date($start_date, $end_date) {
list($start_year, $start_month, $start_day) = explode('-', $start_date);
list($end_year, $end_month, $end_day) = explode('-', $end_date);
$month_diff = $end_month - $start_month;
$day_diff = $end_day - $start_day;
$months = $month_diff + ($end_year - $start_year) * 12;
$days = 0;
if ($day_diff > 0) {
$days = $day_diff;
}
else if ($day_diff < 0) {
$days = $end_day;
$months--;
if ($month_diff > 0) {
$days += 30 - $start_day;
if (in_array($start_month, array(1, 3, 5, 7, 8, 10, 12))) {
$days++;
}
else if ($start_month == 2) {
if (($start_year % 4 == 0 && $start_year % 100 != 0) || $start_year % 400 == 0) {
$days--;
}
else {
$days -= 2;
}
}
if (in_array($end_month - 1, array(1, 3, 5, 7, 8, 10, 12))) {
$days++;
}
else if ($end_month - 1 == 2) {
if (($end_year % 4 == 0 && $end_year % 100 != 0) || $end_year % 400 == 0) {
$days--;
}
else {
$days -= 2;
}
}
}
}
return array($months, $days);
}
list($months, $days) = diff_date('1984-05-26', '2010-04-29');
print $months . ' months and ' . $days . ' days old.';
Output:
314 months and 3 days old.
Edit: I tried to get rid of redundancy in the code, and forgot to rename a variable. This function will now work correctly for diff_date('2010-06-29', '2011-07-01')
.
Edit: Now correctly works for end months occurring after months with 31 or 28/29 days.