【问题标题】:Removing exactly one month from a date从日期中删除恰好一个月
【发布时间】:2013-05-08 17:17:28
【问题描述】:

如果您需要可靠和准确的日期操作,您似乎不能使用strotime。例如,如果该月有 31 天,那么 strtotime 似乎只是减去了 30 天,而不是一整月。

因此,例如,如果$event["EndDate"] 等于“2013-10-31 00:00:01”,则以下代码:

echo date("Y/n/j", strtotime('-1 month', strtotime($event["EndDate"]));

输出:2013/10/1 而不是 2013/09/30

问题:现在我怎么知道不这样做,有没有另一种更准确的方法来使 PHP 减去(或添加)整整一个月,而不仅仅是 30 天?

【问题讨论】:

  • 如果您正在处理带有日期和时间的事件,那么请使用 DateTime 对象让自己的生活更轻松
  • 我认为真正的问题是它从 10 月 31 日减去一个月,返回 9 月 31 日,它不存在,而是转换为 10 月 1 日。如果我在 10 月 29 日获取您的代码并将其提供给它,我会按预期得到 9 月 29 日。
  • @Blazemonger 虽然会被严重破坏。我不敢相信strtotime()(它实际上不是 PHP 的一部分,它是一个底层通用 C 库)有这样的缺陷
  • 由于 2013 年 9 月 31 日不存在,问问自己您希望返回什么。显然,9 月 31 日不是任何语言的任何日期/时间函数的可接受结果。在这种情况下,我认为您不能争辩说 9 月 30 日比 10 月 1 日更(不)正确。重要的是行为是一致的和可预测的,我相信它是,虽然我没有测试它,虽然我可能会在我有时间的时候做,因为这激起了我的好奇心。

标签: php datetime strtotime


【解决方案1】:

主要问题是2013/09/31 不存在,因此更好的方法是使用上个月的first daylast day

$date = new DateTime("2013-10-31 00:00:01");
$date->modify("last day last month");
echo $date->format("Y/n/j"); // 2013/9/30

当日期为2013-10-15

$date = new DateTime("2013-10-15 00:00:01");
$day = $date->format("d");
$year = $date->format("Y");

$date->modify("last day last month");
$month = $date->format("m");

if (checkdate($month, $day, $year)) {
    $date->setDate($year, $month, $day);
}

echo $date->format("Y/n/j"); // 2013-9-15

【讨论】:

  • 如果日期是 2013 年 10 月 15 日,那就不好了——但我现在看到了这个问题。该死!
  • DateTime 非常灵活......我会更新我的代码来展示你如何实现这一点......
【解决方案2】:

你说:-

如果您需要可靠且准确的日期操作,您似乎无法使用 strotime

可以,您只需要知道它的行为方式。你的问题促使我进行了几个测试。


当减去一个月时,PHP 不仅仅是从日期中减去 30 天,尽管它似乎是从您正在查看的单个案例中得出的。事实上,在这种情况下,我的测试 here 表明它将上个月的开始时间增加了 31 天(3 月 3 日的结果向我表明了这一点)。

$thirtyOnedayMonths = array(
    1, 3, 5, 7, 8, 10, 12
);

$oneMonth = new \DateInterval('P1M');
$format = 'Y-m-d';

foreach($thirtyOnedayMonths as $month){
    $date = new \DateTime("2013-{$month}-31 00:00:01");
    var_dump($date->format($format));
    $date->sub($oneMonth);
    var_dump($date->format($format));
}

2013-11-12 和 2013-10-12 之间有 31 天,PHP 正确计算月份减法,如 here 所示。

$date = new \DateTime('2013-11-12 00:00:01');
var_dump($date);
$interval = new DateInterval('P1M');
$date->sub($interval);
var_dump($date);

在您的特定情况下,2013-10-31 - 1 个月是 2013-09-31,它不存在。任何日期/时间函数都需要返回一个有效的日期,而 2013-09-31 则不是。

在这种情况下,如上所述,PHP 似乎在上个月的开始时间增加了 31 天才能到达有效日期。

一旦您知道预期的行为,您就可以进行相应的编程。如果当前行为不适合您的用例,那么您可以扩展 DateTime 类以提供适合您的行为。

我假设 strtotimeDateTime::sub() 的行为相同,this test 建议他们这样做。

$thirtyOnedayMonths = array(
    1, 3, 5, 7, 8, 10, 12
);

$format = 'Y-m-d';

foreach($thirtyOnedayMonths as $month){
    $date = date($format, strtotime('-1 month', strtotime("2013-{$month}-31 00:00:01")));
    var_dump($date);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-15
    • 2017-06-13
    • 1970-01-01
    • 2011-11-29
    • 1970-01-01
    • 1970-01-01
    • 2016-12-10
    • 1970-01-01
    相关资源
    最近更新 更多