Элегантный способ получить количество месяцев между двумя датами?
предположим, что у меня есть две даты в переменных, например
$date1 = "2009-09-01";
$date2 = "2010-05-01";
мне нужно получить количество месяцев между $date2 и $date1($date2 >= $date1). То есть мне нужно получить 8.
есть ли способ получить его с помощью дата функция, или я должен взорвать мои строки и сделать некоторые вычисления?
спасибо
10 ответов:
для 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 возвращает a 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:: diff или вашу СУБД:
$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
или, если вы хотите процедурном стиле:
$date1 = new DateTime("2009-09-01"); $date2 = new DateTime("2010-05-01"); $interval = date_diff($date1, $date2); echo $interval->m + ($interval->y * 12) . ' months';обновление: добавлен бит кода для учета лет.
или простой расчет даст :
$numberOfMonths = abs((date('Y', $endDate) - date('Y', $startDate))*12 + (date('m', $endDate) - date('m', $startDate)))+1;точный и работает во всех случаях.
после тестирования тонны решений, положить все в модульный тест, это то, что я выхожу с:
/** * 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 (как ожидалось).
Это еще один способ, чтобы получить количество месяцев между двумя датами:
// 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; }
Я использую этот:
$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);
используя DateTime, это даст вам более точное решение для любого количества месяцев:
$d1 = new DateTime("2011-05-14"); $d2 = new DateTime(); $d3 = $d1->diff($d2); $d4 = ($d3->y*12)+$d3->m; echo $d4;вам все равно нужно будет обрабатывать оставшиеся дни
$d3->dЕсли ваша реальная проблема не так проста и резка, как исходный вопрос, где обе даты находятся в первом месяце.
Это простой метод, который я написал в своем классе, чтобы подсчитать количество месяцев, участвующих в двух заданных датах:
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; }
я использовал это и работает во всех условиях
$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;
в случае, если даты являются частью результирующего набора из запроса mySQL, гораздо проще использовать функцию TIMESTAMPDIFF для ваших вычислений даты, и вы можете указать единицы возврата, например.
Select TIMESTAMPDIFF(MONTH, start_date, end_date)months_diff from table_name
Comments