PHP:DatePeriod与月的最后一天

时间:2014-09-12 21:27:24

标签: php datetime

我想使用PHP DateInterval迭代几个月:

$from = new DateTime();
$from->setDate(2014, 1, 31);

$period = new DatePeriod($from, new DateInterval('P1M'), 12);

我预计它会在2月28日1月31日返回(因为DateInterval是1个月),但实际上它将于4月31日,3月3日,4月3日返回...因此跳过2月。

有没有办法简单地做到这一点?

谢谢!

编辑:作为参考,这里有一个似乎涵盖大多数用例的解决方案:

$date = new DateTime('2014-01-31');
$start = $date->format('n');

for ($i = 0; $i < 28; $i++) {
  $current = clone $date;
  $current->modify('+'.$i.' month');

  if ($current->format('n') > ($start % 12) && $start !== 12) {
    $current->modify('last day of last month');
  }

  $start++;

  echo $current->format('Y-m-d').PHP_EOL;
}

4 个答案:

答案 0 :(得分:3)

您可以使用DateTime::modify()

$date = new DateTime('last day of january');
echo $date->format('Y-m-d').PHP_EOL;

for ($i = 1; $i < 12; $i++) {
  $date->modify('last day of next month');
  echo $date->format('Y-m-d').PHP_EOL;
}

编辑:我想我不明白你的问题。这是一个新版本:

$date = new DateTime('2014-01-31');

for ($i = 0; $i < 12; $i++) {
  $current = clone $date;
  $current->modify('+'.$i.' month');

  if ($current->format('n') > $i + 1) {
    $current->modify('last day of last month');
  }

  echo $current->format('Y-m-d').PHP_EOL;
}

答案 1 :(得分:0)

您可以尝试这样:

$date = new DateTime();
$lastDayOfMonth = $date->modify(
  sprintf('+%d days', $date->format('t') - $date->format('j'))
);

答案 2 :(得分:0)

我会这样做

$max = array (
31,28,31,30,31,30,31,31,30,31,30,31
); //days in month

$month = 1;
$year = 2014;
$day = 31;

$iterate = 12;
$dates = array();
for ($i = 0;$i < $iterate;$i++) {
    $tmp_month = ($month + $i) % 12;
    $tmp_year = $year + floor($month+$i)/12;
    $tmp_day = min($day, $max[$tmp_month]);
    $tmp = new DateTime();
    $tmp->setDate($tmp_year, $tmp_month + 1, $tmp_day);
    $dates[] = $tmp;
}

var_dump($dates);

如果可能的话,这会保持每个月的同一天

答案 3 :(得分:0)

问题是由该范围内每个月的最后一天之间的差异引起的。即。 2月以28代替31结束,并且从最后一天2014-01-31 + 1 month = 2014-03-03 https://3v4l.org/Y42QJ

开始增加了1个月

要解决DatePeriod的问题并将其简化一点,请使用first day of this month,通过将指定的日期重置为指定月份的第一天来调整初始日期。

然后,在迭代过程中,您可以使用last day of this month来检索当前迭代月份的界限,从而修改日期期限日期。

示例:https://3v4l.org/889mB

$from = new DateTime('2014-01-31');
$from->modify('first day of this month'); //2014-01-01

$period = new DatePeriod($from, new DateInterval('P1M'), 12);
foreach ($period as $date) {
    echo $date->modify('last day of this month')->format('Y-m-d');
}

结果:

2014-01-31
2014-02-28
2014-03-31
2014-04-30
2014-05-31
2014-06-30
2014-07-31
2014-08-31
2014-09-30
2014-10-31
2014-11-30
2014-12-31
2015-01-31

然后在此方法上进行扩展,以便从指定的日期检索所需的日期,例如29th。您可以提取指定的日期,并在该日期超出该月份的范围时根据需要调整当前迭代的月份。

示例:https://3v4l.org/SlEJc

$from = new DateTime('2014-01-29');
$day = $from->format('j');
$from->modify('first day of this month'); //2014-01-01

$period = new DatePeriod($from, new DateInterval('P1M'), 12);
foreach ($period as $date) {
    $lastDay = clone $date;
    $lastDay->modify('last day of this month');
    $date->setDate($date->format('Y'), $date->format('n'), $day);
    if ($date > $lastDay) {
       $date = $lastDay;
    }
    echo $date->format('Y-m-d');
}

结果:

2014-01-29
2014-02-28 #notice the last day of february is used
2014-03-29
2014-04-29
2014-05-29
2014-06-29
2014-07-29
2014-08-29
2014-09-29
2014-10-29
2014-11-29
2014-12-29
2015-01-29