2010-11-20 2 views
45

Предположим, у меня есть две даты в переменных, какЭлегантный способ получить количество месяцев между двумя датами?

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

мне нужно получить количество месяцев между $date2 и $date1 ($date2 >= $date1). То есть Мне нужно получить 8.

Есть ли способ получить его с помощью функции date, или мне нужно взорвать мои строки и выполнить некоторые вычисления?

Спасибо большое

ответ

93

Для 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 :: дифф возвращает объект DateInterval

Если вы не работаете с PHP 5.3 или выше, я думаю, вы» необходимо использовать временные метки unix:

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

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

Но это не очень точный (нет всегда 30 дней в месяц).

Последняя вещь: если эти даты взяты из вашей базы данных, используйте вашу СУБД для выполнения этой работы, а не PHP.

Edit: Этот код должен быть более точным, если вы не можете использовать DateTime :: диф или РСУБД:

$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 
+0

Отличное решение на петле! Очень краткий и точный. Отлично сработано! +1 –

+5

Если у вас есть две даты более чем на год, вы найдете 'var_dump ($ d1-> diff ($ d2) -> m)' приведет вас к отказу в методе DateTime (верхняя часть этого ответа), так как он будут отображаться только месяцы, которые не складываются до нескольких лет. Попробуйте это и посмотрите, что произойдет: '$ d1 = new DateTime (" 2011-05-14 ");' '$ d2 = new DateTime (" 2013-02-02 ");' '$ d3 = $ d1 -> diff ($ d2); ' ' echo '

'.print_r($d3,true).'
'; ' – pathfinder

+0

Ну, не так быстро ... опираясь на strtotime может дать вам головные боли. Сколько месяцев между 31.01.2011 и 28.02.2011? –

23

Или, если вы хотите процедурный стиль:

$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: Добавлен бит кода для учета лет.

+1

Если ваши даты больше чем на год, это не удастся. Вам нужно будет добавить годы * 12 к вашему ответу, чтобы получить месяцы. – pathfinder

+1

Исправить. Обновлено для учета возможных периодов года. –

1

Использование DateTime, это даст вам более точное решение для любого количества месяцев:

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

Вам еще нужно будет обрабатывать оставшиеся дни $d3->d если ваша реальная мировая проблема не так проста, и вырезать и как исходный вопрос, где обе даты находятся в первой половине месяца.

13

Или простой расчет даст:

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

Точная и работает во всех случаях.

+0

Это замечательно, если не считать его всегда 1. Удалите «+1» в конце! : D – supercoolville

11

После тестирования тонн решений, вкладывая все в модульном тесте, это то, что я пришел с:

/** 
* Calculate the difference in months between two dates (v1/18.11.2013) 
* 
* @param \DateTime $date1 
* @param \DateTime $date2 
* @return int 
*/ 
public static function diffInMonths(\DateTime $date1, \DateTime $date2) 
{ 
    $diff = $date1->diff($date2); 

    $months = $diff->y * 12 + $diff->m + $diff->d/30; 

    return (int) round($months); 
} 

Например, он будет возвращать (тестовые случаи из модульного тестирования):

  • 01.11.2013 - 30.11.2013 - 1 месяц
  • 01.01.2013 - 31.12.2013 - 12 месяцев
  • 31.01.2011 - 28.02.2011 - 1 месяц
  • 01.09.2009 - 01.05.2010 - 8 месяцев
  • 01.01.2013 - 31.03.2013 - 3 месяца
  • 15.02.2013 - 15.04.2013 - 2 месяца
  • 01.02.1985 - 31.12.2013 - 347 месяцев

Извещение: Из-за округления он делает с днями, даже половина месяца будет округлена, что может привести к выпуску, если вы используете его в некоторых случаях. Поэтому НЕ ИСПОЛЬЗУЙТЕ его для таких случаев, это вызовет проблемы.

Например:

  • 02.11.2013 - 31.12.2013 возвратит 2, а не 1 (как ожидалось).
+1

Это решение полезно для «человекочитаемого» количества месяцев между: оно возвращает то, что человек ожидал бы увидеть. В этом случае округление, упомянутое выше, действительно полезно, и вы получаете «проблемы» с пользователями, если вы этого не сделаете! – Steve

+0

31.01.2011 - 01.03.2011 - 1 месяц ==> должно быть 2 месяца – manish1706

1

Это простой метод, который я написал в своем классе, чтобы подсчитать количество месяцев, участвующих в двух заданных дат:

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; 
} 
+0

Пока я даю ему +1, так как это наиболее близко, чтобы дать какие-либо реальные результаты. Тем не менее, он не является полным, так как он не удастся указать даты в том же месяце. –

3

Я использую это:

$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); 
3

Это еще один способ для получения количества месяцев между двумя датами:

// 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; 
} 
+0

Это должен быть правильный ответ :) –

0

Я использовал это и работает во всех условиях

$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; 
Смежные вопросы