无法从PHP中的DateTime获取上个月 - 这是一个(相当大的)错误吗?

时间:2010-11-25 17:36:57

标签: php datetime

我需要在PHP中创建函数,让我在给定的日期时间单位上升/下移。具体来说,我需要能够从当前月份转移到下一个/上个月。

我以为我可以使用DateTime :: add / sub(P1M)来做到这一点。然而,当试图获得前一个月时,如果日期值= 31-看起来它实际上试图倒数30天而不是递减月值,则会搞砸!:

$prevMonth = new DateTime('2010-12-31'); 

尝试减少月份:

$prevMonth->sub(new DateInterval('P1M')); // = '2010-12-01'
$prevMonth->add(DateInterval::createFromDateString('-1 month')); // = '2010-12-01'
$prevMonth->sub(DateInterval::createFromDateString('+1 month')); // = '2010-12-01'
$prevMonth->add(DateInterval::createFromDateString('previous month')); // = '2010-12-01'

这肯定是错误的行为。有人有任何见解吗? 谢谢 -

注意: PHP版本5.3.3

4 个答案:

答案 0 :(得分:6)

(信用实际上属于Alex,因为在评论中指出了这一点)

问题不是PHP,而是GNU问题,如下所述:

Relative items in date strings

这里的关键是区分“上个月这个日期”的概念,因为月份是具有不同日期数量的“模糊单位”,因此无法定义像12月31日这样的日期(因为11月31日没有'存在),以及“上个月,不论日期”的概念。

如果我们感兴趣的只是前一个月,那么保证正确的DateInterval计算的唯一方法是将日期值重置为1st,或者每个月将有一些其他数字。

真正令我印象深刻的是这个问题在PHP和其他地方没有记录 - 考虑它可能影响的日期相关软件的数量。

这是一种安全的方法来处理它:

/*
Handles month/year increment calculations in a safe way,
avoiding the pitfall of 'fuzzy' month units.

Returns a DateTime object with incremented month/year values, and a date value == 1.
*/
function incrementDate($startDate, $monthIncrement = 0, $yearIncrement = 0) {

    $startingTimeStamp = $startDate->getTimestamp();
    // Get the month value of the given date:
    $monthString = date('Y-m', $startingTimeStamp);
    // Create a date string corresponding to the 1st of the give month,
    // making it safe for monthly/yearly calculations:
    $safeDateString = "first day of $monthString";
    // Increment date by given month/year increments:
    $incrementedDateString = "$safeDateString $monthIncrement month $yearIncrement year";
    $newTimeStamp = strtotime($incrementedDateString);
    $newDate = DateTime::createFromFormat('U', $newTimeStamp);
    return $newDate;
}

答案 1 :(得分:2)

在我看来,最简单的方法就是使用mktime。

像这样:

$date = mktime(0,0,0,date('m')-1,date('d'),date('Y'));
echo date('d-m-Y', $date);

Greetz Michael

p.s mktime文档可以在这里找到:http://nl2.php.net/mktime

答案 2 :(得分:1)

你可以去上学,只使用日期和strtotime功能。

$date = '2010-12-31';
$monthOnly = date('Y-m', strtotime($date));
$previousMonth = date('Y-m-d', strtotime($monthOnly . ' -1 month'));

答案 3 :(得分:-1)

(这可能应该是一个评论,但它要长一个)

以下是它如何在Windows 7 Apache 2.2.15上使用PHP 5.3.3:

<?php $dt = new DateTime('2010-12-31');
$dt->sub(new DateInterval('P1M'));
print $dt->format('Y-m-d').'<br>';
$dt->add(DateInterval::createFromDateString('-1 month'));
print $dt->format('Y-m-d').'<br>';
$dt->sub(DateInterval::createFromDateString('+1 month'));
print $dt->format('Y-m-d').'<br>';
$dt->add(DateInterval::createFromDateString('previous month'));
print $dt->format('Y-m-d').'<br>'; ?>

2010-12-01
2010-11-01
2010-10-01
2010-09-01

所以这似乎确认它与上面的GNU有关。

注意:IMO下面的代码按预期工作。

 $dt->sub(new DateInterval('P1M'));

本月:12
上个月:11
第12个月的天数:31
第11个月的天数:30
12月31日 - 31日= 11月31日
11月31日= 11月1日+ 31天= 12月1日(30 + 1)