【问题标题】:Unexpected DateTime DateInterval DatePeriod results意外的 DateTime DateInterval DatePeriod 结果
【发布时间】:2014-12-26 10:31:39
【问题描述】:

虽然使用 DateTime DateInterval 和 DatePeriod 来计算两个日期之间的间隔,但在使用 P1W(周)和 P1M(月)时,我遇到了一些意想不到的结果。

如果我们得到 9 月 30 日到 10 月 29 日之间的月份,它只会输出“Sep”。将结束日期更改为 10 月 30 日会输出“Sep”和“Oct”。我的第一个想法是也许它需要是本月的最后一天,但当然,10 月有 31 天......

$dateStart  = '2014-09-30 00:00:00';
$dateEnd    = '2014-10-29 23:59:59'; // Sep
// $dateEnd = '2014-10-30 23:59:59'; // Sep, Oct
// $dateEnd = '2014-10-31 23:59:59'; // Sep, Oct
$dateInt    = 'M';

$start      = new DateTime($dateStart);
$end        = new DateTime($dateEnd);
$interval   = new DateInterval('P1'.$dateInt);
$period     = new DatePeriod($start, $interval, $end);

foreach ($period as $day) {
    var_dump($day->format($dateInt));
}

在尝试获取两个日期之间的周数时会发生同样的事情。将结束日期设置为 10 月 27 日星期一,结果中不包括该周 (44)。但是,将结束日期更改为 10 月 28 日星期二,确实包括第 44 周。

$dateStart  = '2014-09-30 00:00:00';
$dateEnd    = '2014-10-27 23:59:59'; // Monday - 40, 41, 42, 43
// $dateEnd = '2014-10-28 23:59:59'; // Tuesday - 40, 41, 42, 43, 44
// $dateEnd = '2014-10-29 23:59:59'; // Wednesday - 40, 41, 42, 43, 44
$dateInt    = 'W';

$start      = new DateTime($dateStart);
$end        = new DateTime($dateEnd);
$interval   = new DateInterval('P1'.$dateInt);
$period     = new DatePeriod($start, $interval, $end);

foreach ($period as $day) {
    var_dump($day->format($dateInt));
}

有谁知道这是否是一个已知的错误?如果是这样/如果不是,有没有人知道最好的解决方法/修复?

【问题讨论】:

  • 2014-09-30 + 1month = 2014-10-30。由于您的$end 日期早于(或等于)2014-10-30,因此您只会得到一个句点。这不是错误,这是它的工作原理。
  • @Glavić 好点。不敢相信我没有想到。我已经更新了我的“解决方法”来解释这就是为什么这让我绊倒了。

标签: php date datetime


【解决方案1】:

好的,正如 cmets 中所指出的,问题在于我的开始/结束日期不大于我正在检查的时间间隔(即一周或一个月)。愚蠢的球做起来!

因此,一种解决方法是将结束日期设置为一周的最后一天(对于一周)或一个月的最后一天(对于一个月)。为确保开始日期不会发生同样的问题,我们还可以确保开始日期是本周的星期一或本月的第一天。

修正后的月份示例和结果;

$dateStart  = '2014-09-30 00:00:00';
$dateEnd    = '2014-10-29 23:59:59'; // Sep, Oct
// $dateEnd = '2014-10-30 23:59:59'; // Sep, Oct
// $dateEnd = '2014-10-31 23:59:59'; // Sep, Oct
$dateInt    = 'M';

$start      = new DateTime($dateStart);
$end        = new DateTime($dateEnd);

if($dateInt == 'W') {
    $start  = $start->modify('Monday this week');
    $end    = $end->modify('this Sunday');
} else if($dateInt == 'M') {
    $start  = $start->modify('first day of this month');
    $end    = $end->modify('last day of this month');
}

$interval   = new DateInterval('P1'.$dateInt);
$period     = new DatePeriod($start, $interval, $end);

foreach ($period as $day) {
    var_dump($day->format($dateInt));
}

周示例和修复结果;

$dateStart  = '2014-09-30 00:00:00';
$dateEnd    = '2014-10-27 23:59:59'; // Monday - 40, 41, 42, 43, 44
// $dateEnd = '2014-10-28 23:59:59'; // Tuesday - 40, 41, 42, 43, 44
// $dateEnd = '2014-10-29 23:59:59'; // Wednesday - 40, 41, 42, 43, 44
$dateInt    = 'W';

$start      = new DateTime($dateStart);
$end        = new DateTime($dateEnd);

if($dateInt == 'W') {
    $start  = $start->modify('Monday this week');
    $end    = $end->modify('this Sunday');
} else if($dateInt == 'M') {
    $start  = $start->modify('first day of this month');
    $end    = $end->modify('last day of this month');
}

$interval   = new DateInterval('P1'.$dateInt);
$period     = new DatePeriod($start, $interval, $end);

foreach ($period as $day) {
    var_dump($day->format($dateInt));
}

似乎可以解决这个问题。

也可能与这个错误有关 - https://bugs.php.net/bug.php?id=52480

【讨论】:

    【解决方案2】:

    comments 中的文档说明:

    endDate 日期时间被排除在外

    所以 2014-09-30 00:00:00 - 2014-10-30 00:00:00 包含 1 个月

    但是 2014-09-30 00:00:00 - 2014-10-30 00:00:01 包含 2 个月

    此外,文档指出,您甚至可以通过在构造函数方法调用中使用标志来排除 startDate。

    【讨论】:

    • 问题并没有真正归结为结束日期被排除,这是因为我正在比较的日期低于我正在检查的时间间隔 - 很明显现在它已经被指出了,这是一个愚蠢的错误制作。我已经更新了我的答案/解决方法来解释这一点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多