• Status: Solved
• Priority: Medium
• Security: Public
• Views: 1376

# PHP Calc Number of months between 2 dates.

I need to find out how to calculate the number of months between two dates.  Does anyone know a good way to do this with PHP?
0
Tygh2
• 3
• 2
• 2
• +2
2 Solutions

Commented:
<?php
//create two dates using mktime
\$d1 = mktime(0, 0, 0, 4, 5, 2005);
\$d2 = mktime(0, 0, 0, 1, 3, 2003);

//get the year and month for both dates
\$year1 = date("Y", \$d1 );
\$year2 = date("Y", \$d2 );
\$month1 = date("n", \$d1 );
\$month2 = date("n", \$d2 );

//calculate number of months
\$numMonths = abs((\$year1 - \$year2) * 12 + (\$month1 - \$month2));

echo "\\$numMonths is \$numMonths<br />\n";
?>

http://www.php.net/date
0

Author Commented:
This calculation needs to be exactly how many full months.  If it is less than one month between the dates (ex: 03/30/05 and 04/03/05) it would not count as a month between the dates because it has not been a full month yet.
0

Commented:
Try this :

<?
\$date1 = "2005-02-09";
\$date2 = "2006-04-08";

\$ts1 = strtotime(\$date1);
\$ts2 = strtotime(\$date2);

\$months = (date("Y",\$ts2) - date("Y",\$ts1))*12 + (date("m",\$ts2) - date("m",\$ts1)) - (date("d",\$ts2)<date("d",\$ts1)?1:0);

echo \$months;

?>
0

Commented:
Same code as above, but with comments:

<?
\$date1 = "2005-02-09";    // Dates to compare - Lowest date
\$date2 = "2006-10-08";    // Highest date

\$ts1 = strtotime(\$date1); // Creating timestamp of from date
\$ts2 = strtotime(\$date2); // Creating timestamp of to date

/* Calculation:
Differnce in years * 12
+ Differnce in months
- 1 Month if days in "to date" is less than days in "from date".
*/

\$months = (date("Y",\$ts2) - date("Y",\$ts1))*12 + (date("m",\$ts2) - date("m",\$ts1)) - (date("d",\$ts2)<date("d",\$ts1)?1:0);    // Calculation

echo \$months;

?>
0

Commented:
<?php
\$d1 = mktime(0, 0, 0, 3, 30, 2005);
\$d2 = mktime(0, 0, 0, 4, 30, 2005);

\$year1 = date("Y", \$d1 );
\$year2 = date("Y", \$d2 );
\$month1 = date("n", \$d1 );
\$month2 = date("n", \$d2 );
\$day1 = date("d", \$d1 );
\$day2 = date("d", \$d2 );

if( \$d1 > \$d2 ) { //date 1 later than day 2
if(\$day1 - \$day2 < 0 ) //not full month
} else { //date 2 later than day 1
if(\$day2 - \$day1 < 0 ) //not full month
}
\$day1 = date("d", \$d1 );
\$day2 = date("d", \$d2 );

\$numMonths = abs((\$year1 - \$year2) * 12 + (\$month1 - \$month2)) + \$adjust;

echo date("F j, Y", \$d1) . "<br />\n";
echo date("F j, Y", \$d2) . "<br />\n";
echo "\\$numMonths is \$numMonths<br />\n";
?>
0

Commented:
try this too :
<?php
//function
function month_count(\$start_date,\$end_date) {
return date("m",strtotime(\$end_date)-strtotime(\$start_date))-1;
}
//exemples of usage
echo "months =".month_count("03/29/05","03/30/05")."<br>";
echo "months =".month_count("03/30/05","04/03/05")."<br>";
echo "months =".month_count("03/30/05","04/30/05")."<br>";
echo "months =".month_count("03/30/05","05/01/05")."<br>";
?>
0

Commented:
to make it work with different years (without assuming a month is 30 days)
//function
function month_count(\$start_date,\$end_date) {
\$start_timestamp = strtotime(\$start_date);
\$end_timestamp = strtotime(\$end_date);
\$x = split(",", date("Y,m", \$end_timestamp-\$start_timestamp));
return ((\$x[0] - 1970)*12 + (\$x[1] - 1));
}

//usage
echo "months =".month_count("03/29/05","03/30/05")."<br>";
echo "months =".month_count("03/30/05","04/03/05")."<br>";
echo "months =".month_count("03/30/05","04/30/05")."<br>";
echo "months =".month_count("01/01/05","12/31/05")."<br>";
echo "months =".month_count("01/01/05","01/01/06")."<br>";
?>
0

Commented:
Hi

alextr2003fr: I like the idea that you've used, it's a clever solution, but I think there may be problems with leap years.  I'm going to try out some tougher ones on it!

Here was my idea...

function monthsdiff(\$date1, \$date2)
{
// Split to year, month, day
list(\$y1, \$m1, \$d1) = explode('-', date('Y-m-d', \$date1));
list(\$y2, \$m2, \$d2) = explode('-', date('Y-m-d', \$date2));
// Number of months
\$n = (\$y2 - \$y1) * 12 + (\$m2 - \$m1);
// If day(2) is earlier than day(1) - 1 then decrement
if (\$d2 < \$d1 - 1) \$n--;
return \$n;
}

\$date1 = mktime(0, 0, 0, 10, 5, 2005);
\$date2 = mktime(0, 0, 0, 11, 4, 2005);

echo monthsdiff(\$date1, \$date2);

... I'm assuming that for example 10/5/2005-11/4/2005 is a whole month?  It depends how you want to look at it.  If you want that to be zero, and 10/5/2005-11/5/2005 to be 1 then just change this ...
// If day(2) is earlier than day(1) - 1 then decrement
if (\$d2 < \$d1 - 1) \$n--;
... to this ...
// If day(2) is earlier than day(1) then decrement
if (\$d2 < \$d1) \$n--;

HTH

Hamlet
0

Commented:
Hmm ... I just realised there are some other tricky situations.  I'm not sure how you would want to handle these ones.  Again it depends on what you are using it for.

How many months are there between 1/31/05 and 2/28/05?

Intuitively speaking I would say that is the whole of February, so it is one month.  My example though would say it is 0.

What do you think?

To some extent it also relates to my previous comment about dates like 10/5/2005-11/4/2005.  If that is a whole month then this case needs some more thought.  If on the other hand you would want that to return 0, then this case actually becomes irrelevant, because by the same logic 1/31/05 to 2/28/05 should also be 0.
0

Author Commented:
Hamlet,

You are right, there is 1 month between 1/31/05 and 2/28/05.  The same problem will occur with other months that end with 30.  This is for a payment program that needs to account for the number of payments missed if they are late on their monthly payments.  So somehow this needs to be accounted for.
0

Commented:
Ok, well the main question revolves around how to treat our partial months IE the first and last month of the timespan.  For example, if our dates are 1/30/04 and 2/28/05 the partial months will be January and February.  So here we have a year (12 months) plus 2 days from January and 28 days from February for a total of 12 months and 29 days (while 2+28 = 30, we only count 29 since we assume a common timepoint between days, rather than counting all of January 30th and all of February 28th to add in the additional day...).  While 29 days is *not* a month when compared to January (because of January's 31 days) it *will* be a month when compared to February's 28 Days.  So we'd have 13 months for this timespan.

For 12/31/04 and 1/30/05, we'd have a total of 30 partial days which is not greater than the number of days in December or January, so we will have no months for this timespan.

For 3/31/05 and 4/30/05, we'd have a total of 30 parital days again, but it would be equal to the total number of days in April, and thus would be counted as a month.

We use date( "t", ... ) to check the number of days in the months.  See the sample code below:

<?php

function calcMonths( \$d1, \$d2 ) {

if( \$d1 > \$d2 ) {//if date 1 later than date 2, swap the dates
\$temp = \$d2;
\$d2 = \$d1;
\$d1 = \$temp;
}

//d1 now represents oldest date, d2 most recent date

\$year1 = date("Y", \$d1 );
\$year2 = date("Y", \$d2 );
\$month1 = date("n", \$d1 );
\$month2 = date("n", \$d2 );
\$day1 = date("d", \$d1 );
\$day2 = date("d", \$d2 );

//now lets check the number of total partial days we have
//IE the first and last months

//get number of days in first and last month
\$numDays1stMo = date("t", \$d1);
\$numDays2ndMo = date("t", \$d2);
//get add together total number of partial days
\$partialMonthDays = (\$numDays1stMo - \$day1 + 1) + \$day2 - 1;
//#days in first month is (total days in month) minus (day #) + 1
//#days in last month is simply the (day #)

//comment these echos out
echo "\\$partialMonthDays is \$partialMonthDays<br />\n";
echo "\\$numDays1stMo is \$numDays1stMo<br />\n";
echo "\\$numDays2ndMo is \$numDays2ndMo<br />\n";
echo "\\$numDays1stMo[\$numDays1stMo] - \\$day1[\$day1] + \\$day2[\$day2] <br />\n";

//if our total number of days is greater than the number of days
//in either of these months, we'll count it as a full month

//so if the negation of this logic is true, we don't count it, and adjust downwards
if( !(\$partialMonthDays >= \$numDays1stMo || \$partialMonthDays >= \$numDays2ndMo) ) {
}

//perform month calculation
\$numMonths = (\$year2 - \$year1) * 12 + (\$month2 - \$month1) + \$adjust;

return \$numMonths;
}

\$d1 = mktime(0, 0, 0, 1, 30, 2005);
\$d2 = mktime(0, 0, 0, 2, 28, 2005);

echo date("F j, Y", \$d1) . "<br />\n";
echo date("F j, Y", \$d2) . "<br />\n";
echo "\\$numMonths is " . calcMonths( \$d1, \$d2 ) . "<hr />\n";

\$d3 = mktime(0, 0, 0, 12, 31, 2004);
\$d4 = mktime(0, 0, 0, 1, 30, 2005);

echo date("F j, Y", \$d3) . "<br />\n";
echo date("F j, Y", \$d4) . "<br />\n";
echo "\\$numMonths is " . calcMonths( \$d3, \$d4 ) . "<hr />\n";

\$d5 = mktime(0, 0, 0, 3, 31, 2005);
\$d6 = mktime(0, 0, 0, 4, 30, 2005);

echo date("F j, Y", \$d5) . "<br />\n";
echo date("F j, Y", \$d6) . "<br />\n";
echo "\\$numMonths is " . calcMonths( \$d5, \$d6 ) . "<hr />\n";
?>
0

## Featured Post

• 3
• 2
• 2
• +2
Tackle projects and never again get stuck behind a technical roadblock.