PHP:DatePeriod与月份的最后一天

PHP:DatePeriod与月份的最后一天,php,datetime,Php,Datetime,我想使用PHP DateInterval迭代几个月: $from = new DateTime(); $from->setDate(2014, 1, 31); $period = new DatePeriod($from, new DateInterval('P1M'), 12); 我希望它返回1月31日,2月28日(因为日期间隔是1个月),但实际上它返回1月31日,3月3日,4月3日。。。因此跳过了二月 有什么简单的方法可以做到这一点吗 谢谢 编辑:作为参考,这里有一个解决方案似乎涵

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

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

$period = new DatePeriod($from, new DateInterval('P1M'), 12);
我希望它返回1月31日,2月28日(因为日期间隔是1个月),但实际上它返回1月31日,3月3日,4月3日。。。因此跳过了二月

有什么简单的方法可以做到这一点吗

谢谢

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

$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;
}
$date=新日期时间('2014-01-31');
$start=$date->format('n');
对于($i=0;$i<28;$i++){
$current=clone$date;
$current->modify(“+”.$i.“month”);
如果($current->format('n')>($start%12)&&$start!==12){
$current->modify('last day of last month');
}
$start++;
echo$current->format('Y-m-d')。PHP\u EOL;
}
您可以这样尝试:

$date = new DateTime();
$lastDayOfMonth = $date->modify(
  sprintf('+%d days', $date->format('t') - $date->format('j'))
);
您可以使用:

$date=新的日期时间(“1月的最后一天”);
echo$date->format('Y-m-d')。PHP\u EOL;
对于($i=1;$i<12;$i++){
$date->modify(‘下个月的最后一天’);
echo$date->format('Y-m-d')。PHP\u 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;
}
$date=新日期时间('2014-01-31');
对于($i=0;$i<12;$i++){
$current=clone$date;
$current->modify(“+”.$i.“month”);
如果($current->format('n')>$i+1){
$current->modify('last day of last month');
}
echo$current->format('Y-m-d')。PHP\u EOL;
}

我可能会这样做

$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);
$max=array(
31,28,31,30,31,30,31,31,30,31,30,31
); //月份天数
$month=1;
$year=2014年;
$day=31;
$iterate=12;
$dates=array();
对于($i=0;$i<$iterate;$i++){
$tmp_月=($month+$i)%12;
$tmp_year=$year+下限($month+$i)/12;
$tmp_day=min($day,$max[$tmp_month]);
$tmp=新的日期时间();
$tmp->setDate($tmp\U年,$tmp\U月+1,$tmp\U日);
$dates[]=$tmp;
}
var_dump(日期);

如果可能,这将保持每月的同一天

该问题是由范围内每个月的最后一天之间的差异引起的。也就是说,2月28日结束,而不是31日结束,并且从最后一天开始增加1个月的时间
2014-01-31+1个月=2014-03-03

要解决
DatePeriod
的问题并将其简化一点,请使用
本月第一天
将指定日期重置为指定月份的第一天,从而调整初始日期

然后在迭代过程中,您可以使用
本月的最后一天
来修改日期周期日期,以检索当前迭代月份的边界

例子: 结果:

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

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

例子: 结果:

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

这只在您需要当月最后一天时有效。事实上,我想迭代,使它在所有情况下都能工作(因此,它也应该从1月2日开始每月迭代)。用新代码更新了我的答案。你能测试一下,让我知道这是否是你想要的吗?是的,我在二月份尝试了各种edge案例,似乎效果非常好!(尽管我仍然发现DatePeriod的行为不符合逻辑…)。事实上,在某些情况下,它会失败:如果您将12个月更改为24个月,它将从2015年开始失败;)。我将试着看看如何解决这个问题。实际上非常简单,只需要做一个模12:if($current->format('n')>($I%12)+1。但是现在它在其他情况下失败了(例如,如果你不在一月份开始)。这似乎是“不那么糟糕”的解决方案。尽管我担心它需要一些调整(比如考虑到2月份有29天的年份)。
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
$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