计数天“忘记”最后一天

问题描述 投票:0回答:2

我使用这个代码,并能正常工作至今:

<?php

$start = (new DateTime('2019-02-11'));
$end = (new DateTime('2019-04-23'));

$months = new DatePeriod($start, DateInterval::createFromDateString('1 month'), $end);
$days = new DatePeriod($start, DateInterval::createFromDateString('1 day'), $end);

echo "<table border=1><tr>";

foreach ($months as $month){

  echo "<td>".$month->format("M");

  foreach ($days as $day)
    {
      if($month->format("M")==$day->format("M")){$d++;}
    }

  echo " (".$d." days)</td>";

  unset($d);

}

echo "</tr></table>";

?>

输出是:

月(18天)月(31天)月(22天)

不幸的是,“forgots”四月之以某种方式的最后一天(必须是23天像$到底说明)。

为什么代码不算/包括的最后一天?

我是否需要像“加1日”添加到$结束日期?

感谢大伙们!

php date
2个回答
0
投票

您的结束日期时间戳00:00:00这意味着,根据DateTime间隔对象,天还没有实际尚未开始。如果你改变你的$end$end = (new DateTime('2019-04-23 01:00:00'));它将包括这一天为好。

此外,你应该很可能在你的foreach循环添加$d = 0;几个月。现在你没有定义它。 (默认是0,所以它仍然有效,但最好还是自己定义。)


0
投票

我有Dirks answer不同意。使用\DateTime每天从零开始(00:00:00)。

可测试用:

<?php

$start = new \DateTimeImmutable('2019-02-10 23:59:57');
for ($i = 0; $i < 7; ++$i) {
    echo $start->format('c'), "\n";
    $start = $start->modify('+1 second');
}

这说明(我的时区):

2019-02-10T23:59:57+01:00
2019-02-10T23:59:58+01:00
2019-02-10T23:59:59+01:00
2019-02-11T00:00:00+01:00
2019-02-11T00:00:01+01:00
2019-02-11T00:00:02+01:00
2019-02-11T00:00:03+01:00

https://3v4l.org/8Q3kb


与您的代码的问题,是\DatePeriod排除结束日期。并且这样的内循环,每天运行短。

<?php

$start = new \DateTimeImmutable('2019-02-11');
$end = $start->modify('+3 days');

$period = new \DatePeriod($start, new \DateInterval('P1D'), $end);
foreach ($period as $date) {
    echo $date->format('c'), "\n";
}

echo 'actual end date: ', $end->format('c');

# 2019-02-11T00:00:00+01:00
# 2019-02-12T00:00:00+01:00
# 2019-02-13T00:00:00+01:00
# actual end date: 2019-02-14T00:00:00+01:00

但整体的做法是有点过分。例如,下面给出与(IMO)更好的语义和只有最小循环的相同的结果:

<?php

/**
 * @param DateTimeImmutable $start
 * @param DateTimeImmutable $end
 *
 * @return Generator
 */
function remainingDaysPerMonthBetween(\DateTimeImmutable $start, \DateTimeImmutable $end): \Generator {
    while ($start < $end) {
        $diff = $start->diff(min(
            $start->modify('last day of this month'),
            $end
        ));

        yield [$start, $diff->days];

        $start = $start->modify('first day of next month');
    }
}

$start = new \DateTimeImmutable('2019-02-11');
$end = new \DateTimeImmutable('2019-04-23');

foreach (remainingDaysPerMonthBetween($start, $end) as [$date, $remainingDays]) {
    printf("%s: %d\n", $date->format('M'), $remainingDays + 1);
}

https://3v4l.org/BCAYq

© www.soinside.com 2019 - 2024. All rights reserved.