如何列出两个日期之间的所有月份

69

我想列出两个日期之间的所有月份。

例如:开始日期为:2010-12-02,结束日期为:2012-05-06

我想要列出类似以下的内容:

2010-12
2011-01
2011-02
2011-03
2011-04
.
.
.
2012-04
2012-05

这是我尝试过的,但根本没有起作用:

    $year_min = 2010;
    $year_max = 2012;
    $month_min = 12;
    $month_max = 5;
    for($y=$year_min; $y<=$year_max; $y++)
    {
        for($m=$month_min; $m<=$month_max; $m++)
        {
            $period[] = $y.$m;
        }
    }
6个回答

234

PHP 5.3

$start    = new DateTime('2010-12-02');
$start->modify('first day of this month');
$end      = new DateTime('2012-05-06');
$end->modify('first day of next month');
$interval = DateInterval::createFromDateString('1 month');
$period   = new DatePeriod($start, $interval, $end);

foreach ($period as $dt) {
    echo $dt->format("Y-m") . "<br>\n";
}

查看实例

需要 PHP 5.4 或更新版本。

$start    = (new DateTime('2010-12-02'))->modify('first day of this month');
$end      = (new DateTime('2012-05-06'))->modify('first day of next month');
$interval = DateInterval::createFromDateString('1 month');
$period   = new DatePeriod($start, $interval, $end);

foreach ($period as $dt) {
    echo $dt->format("Y-m") . "<br>\n";
}

我们修改开始和结束日期为当月的第一天的部分非常重要。如果我们不这样做,当前日期高于二月的最后一天(即在非闰年是28天,在闰年是29天),这将会跳过二月。


1
PHP 5.4或更高版本中有错误吗?在5.4以下的版本中是$end->modify('first day of next month');,而在5.4以上的版本中是->modify('first day of this month'); - Krewetka
1
@Martin 只需将结果放入一个数组中并反转它。 - John Conde
交换 new DatePeriod($end, $interval, $start) 和 array_reverse(iterator_to_array($period))。 - Adler Dias
echo(iterator_count($period)); - John Conde
这是解决日期太接近的最佳方法示例:var date1 = "2022-09-29"; var date2 = "2022-10-10"; - Bekti Galan
显示剩余2条评论

13
function getMonthsInRange($startDate, $endDate)
{
    $months = array();

    while (strtotime($startDate) <= strtotime($endDate)) {
        $months[] = array(
            'year' => date('Y', strtotime($startDate)),
            'month' => date('m', strtotime($startDate)),
        );

        // Set date to 1 so that new month is returned as the month changes.
        $startDate = date('01 M Y', strtotime($startDate . '+ 1 month'));
    }

    return $months;
}

3
请问您能否说明这为什么有帮助呢? - durron597

10

您必须区分同一年的两个月份和不同年份的两个月份。

$year_min = substr($row['contractStart'], 0, 4);
$year_max = substr($row['contractEnd'], 0, 4);
$month_min = substr($row['contractStart'], 5, 2);
$month_min = substr($row['contractEnd'], 5, 2);
$period = array();
try {
  if ($year_min > $year_max)
    throw new Exception();
  else if ($year_min == $year_max)
    if ($month_min > $month_max)
      throw new Exception();
    for ($month = $month_min; $month <= $month_max; $month++) {
      $period[] = $month . '-' . $year;
    }
  else {
    for ($month = $month_min; $month <= 12; $month++) {
      $period[] = $month . '-' . $year_min;
    }
    for ($year = $year_min + 1; $year < $year_max; $year++) {
      for ($month = $month_min; $month <= $month_max; $month++) {
        $period[] = $month . '-' . $year;
      }
    }
    for ($month = 1; $month <= $month_max; $month++) {
      $period[] = $month . '-' . $year_max;
    }
  }
  implode("<br />\r\n", $period);
}
catch (Exception $e) {
  echo 'Start date occurs after end date.'
}

那是较难的方法。现在已经有一个快速简便的方法给出了答案,我建议您选择它。


5

由于我的服务器环境中没有 DateTime 可用,所以这是我的解决方案。

$a = "2007-01-01";
$b = "2008-02-15";

$i = date("Ym", strtotime($a));
while($i <= date("Ym", strtotime($b))){
    echo $i."\n";
    if(substr($i, 4, 2) == "12")
        $i = (date("Y", strtotime($i."01")) + 1)."01";
    else
        $i++;
}

Try it out: http://3v4l.org/BZOmb


2
在 Laravel 中,
$period = \Carbon\CarbonPeriod::create('2017-06-28', '1 month', '2019-06-01');

foreach ($period as $dt) {
     echo $dt->format("Y-m") . "<br>\n";
}

在2019年的https://dev59.com/WF4b5IYBdhLWcg3wchbs#56234717中提到 - mickmackusa

0

2021年10月更新
如果用户选择了日期,这是一个解决方案

$from = date('Y-m-d', strtotime($_POST['from']));
$to = date('Y-m-d', strtotime($_POST['to']));

$counter = 1;
$max_date = strtotime($to);
$current_date = strtotime($from);
$dates = [];
$months = [];
$loop = true;
while($loop) {
    if(strtotime(date('Y-m-d',$current_date)." +".$counter."days") >= $max_date) $loop = false;
    else {
        $current_date = strtotime(date('Y-m-d', $current_date)." +".$counter."days");
        $date = date('Y-m-d', $current_date);
        $dates[] = $date;
        $months[] = date('Y-m', $current_date);
        $counter++;
    }
}
$months = array_unique($months);
echo '<pre>';
print_r($dates);
echo '<br>';
print_r($months);
echo '</pre>';

即使用户选择了日期,您仍应该使用datetime对象。这个答案太复杂了,缺少教育性的解释。 - mickmackusa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接