简体   繁体   中英

DateTime modify function skips February

When adding a month to with DateTime::modify method, the result skips February.

  • Why isn't it outputing 2020-02-31 ?
  • How to output 2020-02-29 using DateTime? (Last day of the month).
$date = new DateTime("2020-01-31");
echo $date->modify("+1 month")->format("Y-m-d"); // 2020-03-02

PHP DateTime::modify("+n month") adds between 28 to 31 days to the current day, depending of the month and year.

Solution

I suggest you increment months from the first day of the month by using the modify and format methods:

// Instanciates the DateTime object.
$date = new DateTime("2020-01-01");

// Adds a month to the date.
$date->modify("+1 month"); // 2020-02-01

// Format the date with "t" (gets the last day of the month).
$date->format("Y-m-t"); // 2020-02-29

Incrementing from the first day of the month will never raise the February problem which is quite a quite common, thinking that PHP DateTime will smartly add a month from 2020-02-29 and output 2020-03-31 .

Why it happens?

In the Gregorian calendar , the average length of a month is 30.436875 days:

  • 30 days in April, June, September and November;
  • 31 days in January, March, May, July, August, October and December;
  • 28 days or 29 days (in leap years ) in February.

PHP will add to the current date the exact number of days there is in the given month.

Thus, PHP will adjust the date after the first increntation if you are incrementing from the last day of the month.

Eg:

Let's add a month from the final day of March (31th).

Since the current month (March) has 31 days in it, PHP will increment 31 days to the date. Adding 31 days from 2020-03-31 will result in skipping the whole month of April.

$date = new DateTime("2020-03-31");              // 2020-03-31
echo $date->modify("+1 month")->format("Y-m-d"); // 2020-05-01 | Added 31 days (since March has 31 days).
echo $date->modify("+1 month")->format("Y-m-d"); // 2020-06-01 | Added 31 days (since the new date is May 1st, which is a month with 31 days).
echo $date->modify("+1 month")->format("Y-m-d"); // 2020-07-01 | Added 30 days

Now, let's add a month to the final day of April (30th).

We can see that since the next months all have 30+ days in it, final day will stay the same, until February of the next year . Since February always has between 28 and 29 days, adding 31 days to it will pass the month, and resulting date will be March 2nd.

$date = new DateTime("2020-04-30");
echo $date->modify("+1 month")->format("Y-m-d"); // 2020-05-30 | Added 30 days.
echo $date->modify("+1 month")->format("Y-m-d"); // 2020-06-30 | Added 31 days.
echo $date->modify("+1 month")->format("Y-m-d"); // 2020-07-30 | Added 30 days.
// ...
echo $date->modify("+1 month")->format("Y-m-d"); // 2021-01-30 | Added 31 days
echo $date->modify("+1 month")->format("Y-m-d"); // 2021-03-02 | Added 31 days (since January has 31 days).
echo $date->modify("+1 month")->format("Y-m-d"); // 2021-04-02 | Added 31 days (since the new date is March 2nd, which is a month with 31 days).

This is why it is recommended to increment months from the first day of the month, since the 1st is common to all months.

$date = new DateTime("2020-01-01");              // 2020-01-01
echo $date->modify("+1 month")->format("Y-m-d"); // 2020-02-01 | Added 31 days
echo $date->modify("+1 month")->format("Y-m-d"); // 2020-03-01 | Added 29 days (since 2020 is leap year, yee haw).
echo $date->modify("+1 month")->format("Y-m-d"); // 2020-04-01 | Added 31 days

I'm making an assumption that you are programming in php. If so, the documentation indicates that you will receive the results you are getting php DateTime::modify() .

The documentation specifically indicates to "Beware"

Example #2 Beware when adding or subtracting months

 <?php
 $date = new DateTime('2000-12-31');

 $date->modify('+1 month');
 echo $date->format('Y-m-d') . "\n";

 $date->modify('+1 month');
 echo $date->format('Y-m-d') . "\n";
 ?>
 The above example will output:

 2001-01-31
 2001-03-03

If you just need to move to the end of the next +1 month, what we often do in R is go to the end of the current month and then add +1 day and then go to the end of the month again. If you know that you are always at the end of the month, then just add +1 day and then go to the end of the month.

Other posts have some additional suggestions in this space How to find the last day of the month from date?

Example from this post:

 $date = new DateTime('now');
 $date->modify('last day of this month');
 echo $date->format('Y-m-d');

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM