Removing exactly one month from a date

时光怂恿深爱的人放手 提交于 2019-11-28 06:29:10

问题


It seems that you can't use strotime if you need reliable and accurate date manipulation. For example, if the month has 31 days, then it appears that strtotime simply minuses 30 days, not a whole month.

So, for example, if $event["EndDate"] is equal to "2013-10-31 00:00:01", the following code:

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

Ouputs: 2013/10/1 instead of 2013/09/30.

QUESTION: Now how I know how NOT to do it, is there another, more accurate, way to make PHP subtract (or add) exactly a whole month, and not just 30 days?


回答1:


The main issue is that 2013/09/31 does not exist so a better approach would be to use first day or last day of the previous month.

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

When date is 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



回答2:


You say:-

It seems that you can't use strotime if you need reliable and accurate date manipulation

You can, you just need to know how it behaves. Your question prompted me to run a couple of tests.


PHP does not merely subtract 30 days from the date when subtracting a month, although it appears that it does from the single case you are looking at. In fact my test here suggests that it adds 31 days to the start of the previous month (the result of 3rd March suggests this to me) in this case.

$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));
}

There are 31 days between 2013-11-12 and 2013-10-12 and PHP calculates the month subtraction correctly as can be seen here.

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

In your particular case 2013-10-31 - 1 month is 2013-09-31 which does not exist. Any date/time function needs to return a valid date, which 2013-09-31 is not.

In this case PHP, as I stated above, seems to add 31 days to the start of the previous month to arrive at a valid date.

Once you know the expected behaviour, you can program accordingly. If the current behaviour does not fit your use case then you could extend the DateTime class to provide behaviour that works for you.

I have assumed that strtotime and DateTime::sub() behave the same, this test suggests they do.

$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);
}


来源:https://stackoverflow.com/questions/16446564/removing-exactly-one-month-from-a-date

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!