65

Let's assume I have two dates in variables, like

$date1 = "2009-09-01";
$date2 = "2010-05-01";

I need to get the count of months between $date2 and $date1($date2 >= $date1). I.e. i need to get 8.

Is there a way to get it by using date function, or I have to explode my strings and do required calculations?

Thanks.

Simon
  • 22,637
  • 36
  • 92
  • 121

10 Answers10

129

For PHP >= 5.3

$d1 = new DateTime("2009-09-01");
$d2 = new DateTime("2010-05-01");

var_dump($d1->diff($d2)->m); // int(4)
var_dump($d1->diff($d2)->m + ($d1->diff($d2)->y*12)); // int(8)

DateTime::diff returns a DateInterval object

If you don't run with PHP 5.3 or higher, I guess you'll have to use unix timestamps :

$d1 = "2009-09-01";
$d2 = "2010-05-01";

echo (int)abs((strtotime($d1) - strtotime($d2))/(60*60*24*30)); // 8

But it's not very precise (there isn't always 30 days per month).

Last thing : if those dates come from your database, then use your DBMS to do this job, not PHP.

Edit: This code should be more precise if you can't use DateTime::diff or your RDBMS :

$d1 = strtotime("2009-09-01");
$d2 = strtotime("2010-05-01");
$min_date = min($d1, $d2);
$max_date = max($d1, $d2);
$i = 0;

while (($min_date = strtotime("+1 MONTH", $min_date)) <= $max_date) {
    $i++;
}
echo $i; // 8
Pez Cuckow
  • 14,048
  • 16
  • 80
  • 130
Vincent Savard
  • 34,979
  • 10
  • 68
  • 73
  • 1
    Great solution on the while loop! Very concise and accurate. Well done! +1 – Chuck Burgess Nov 20 '10 at 16:40
  • 7
    If you have two dates more than a year apart you will find `var_dump($d1->diff($d2)->m)` will fail you in the DateTime method (the top one on this answer) since it will only show the months that do not add up to years. Try this and see what happens: `$d1 = new DateTime("2011-05-14");` `$d2 = new DateTime("2013-02-02");` `$d3 = $d1->diff($d2);` `echo '
    '.print_r($d3,true).'
    ';`
    – pathfinder Mar 30 '13 at 05:56
  • Well no so fast... relying on strtotime can give you headaches. How many months are between 31.01.2011 and 28.02.2011? – Valentin Despa Jun 13 '13 at 08:16
  • This doesn't work, for the example you've provided it will return 5 not 8 – Pez Cuckow Aug 30 '13 at 19:38
  • @PezCuckow: I actually just tested it again. They all work correctly. – Vincent Savard Aug 31 '13 at 19:41
  • Wrong! Just try 2018-01-01 and 2018-01-03. You'll get 1 month instead of 2! (Tested the "diff" approach) – fishbone May 28 '18 at 11:04
36

Or, if you want the procedural style:

$date1 = new DateTime("2009-09-01");
$date2 = new DateTime("2010-05-01");
$interval = date_diff($date1, $date2);
echo $interval->m + ($interval->y * 12) . ' months';

UPDATE: Added the bit of code to account for the years.

Chuck Burgess
  • 11,600
  • 5
  • 41
  • 74
20

Or a simple calculation would give :

$numberOfMonths = abs((date('Y', $endDate) - date('Y', $startDate))*12 + (date('m', $endDate) - date('m', $startDate)))+1;

Accurate and works in all cases.

Rob
  • 4,927
  • 12
  • 49
  • 54
Mic
  • 201
  • 2
  • 2
  • This is great, except its always off by 1. Remove the "+1" at the end! :D – supercoolville Aug 02 '15 at 20:16
  • This is exactly what I need (with the +1 at the end). It gives you the affected number of month. e.g. from 2018-10-29 till 2018-12-31 are 3 months affected. – Martin Oct 16 '18 at 19:27
4

This is another way to get the number of months between two dates:

// Set dates
$dateIni = '2014-07-01';
$dateFin = '2016-07-01';

// Get year and month of initial date (From)
$yearIni = date("Y", strtotime($dateIni));
$monthIni = date("m", strtotime($dateIni));

// Get year an month of finish date (To)
$yearFin = date("Y", strtotime($dateFin));
$monthFin = date("m", strtotime($dateFin));

// Checking if both dates are some year

if ($yearIni == $yearFin) {
   $numberOfMonths = ($monthFin-$monthIni) + 1;
} else {
   $numberOfMonths = ((($yearFin - $yearIni) * 12) - $monthIni) + 1 + $monthFin;
}
Bekarys
  • 25
  • 1
  • 5
3

I use this:

$d1 = new DateTime("2009-09-01");
$d2 = new DateTime("2010-09-01");
$months = 0;

$d1->add(new \DateInterval('P1M'));
while ($d1 <= $d2){
    $months ++;
    $d1->add(new \DateInterval('P1M'));
}

print_r($months);
manix
  • 14,537
  • 11
  • 70
  • 107
2

Using DateTime, this will give you a more accurate solution for any amount of months:

$d1 = new DateTime("2011-05-14");
$d2 = new DateTime();
$d3 = $d1->diff($d2);
$d4 = ($d3->y*12)+$d3->m;
echo $d4;

You would still need to handle the leftover days $d3->d if your real world problem is not as simple and cut and dry as the original question where both dates are on the first of the month.

pathfinder
  • 1,606
  • 18
  • 22
1

This is a simple method I wrote in my class to count the number of months involved into two given dates :

public function nb_mois($date1, $date2)
{
    $begin = new DateTime( $date1 );
    $end = new DateTime( $date2 );
    $end = $end->modify( '+1 month' );

    $interval = DateInterval::createFromDateString('1 month');

    $period = new DatePeriod($begin, $interval, $end);
    $counter = 0;
    foreach($period as $dt) {
        $counter++;
    }

    return $counter;
}
pollux1er
  • 5,372
  • 5
  • 37
  • 36
  • While I give it a +1 since this is the closest to give any real results. Still it is not complete, since it will fail for dates in the same month. – Mujnoi Gyula Tamas Dec 21 '16 at 20:50
0

In case the dates are part of a resultset from a mySQL query, it is much easier to use the TIMESTAMPDIFF function for your date calculations and you can specify return units eg. Select TIMESTAMPDIFF(MONTH, start_date, end_date)months_diff from table_name

Poly
  • 13
  • 3
0

strtotime is not very precise, it makes an approximate count, it does not take into account the actual days of the month.

it's better to bring the dates to a day that is always present in every month.

$date1 = "2009-09-01";
$date2 = "2010-05-01";

$d1 = mktime(0, 0, 1, date('m', strtotime($date1)), 1, date('Y', strtotime($date1)));
$d2 = mktime(0, 0, 1, date('m', strtotime($date2)), 1, date('Y', strtotime($date2)));

 $total_month = 0;
 while (($d1 = strtotime("+1 MONTH", $d1)) <= $d2) {
     $total_month++;
 }
echo $total_month;
Claudio
  • 60
  • 3
-1

I have used this and works in all conditions

$fiscal_year = mysql_fetch_row(mysql_query("SELECT begin,end,closed FROM fiscal_year WHERE id = '2'"));


            $date1 = $fiscal_year['begin'];
            $date2 = $fiscal_year['end'];

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


            $te=date('m',$ts2-$ts1);

            echo $te;
ranojan
  • 819
  • 8
  • 11