Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP DateTime::modify adding and subtracting months

Tags:

date

php

datetime

I've been working a lot with the DateTime class and recently ran into what I thought was a bug when adding months. After a bit of research, it appears that it wasn't a bug, but instead working as intended. According to the documentation found here:

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 

Can anyone justify why this isn't considered a bug?

Furthermore does anyone have any elegant solutions to correct the issue and make it so +1 month will work as expected instead of as intended?

like image 739
tplaner Avatar asked Aug 30 '10 16:08

tplaner


People also ask

Can I subtract dates in PHP?

The date_sub() is an inbuilt function in PHP which is used to subtract some days, months, years, hours, minutes, and seconds from given date. The function returns a DateTime object on success and returns FALSE on failure.

What is Strtotime PHP?

The strtotime() function parses an English textual datetime into a Unix timestamp (the number of seconds since January 1 1970 00:00:00 GMT). Note: If the year is specified in a two-digit format, values between 0-69 are mapped to 2000-2069 and values between 70-100 are mapped to 1970-2000.


2 Answers

Why it's not a bug:

The current behavior is correct. The following happens internally:

  1. +1 month increases the month number (originally 1) by one. This makes the date 2010-02-31.

  2. The second month (February) only has 28 days in 2010, so PHP auto-corrects this by just continuing to count days from February 1st. You then end up at March 3rd.

How to get what you want:

To get what you want is by: manually checking the next month. Then add the number of days next month has.

I hope you can yourself code this. I am just giving what-to-do.

PHP 5.3 way:

To obtain the correct behavior, you can use one of the PHP 5.3's new functionality that introduces the relative time stanza first day of. This stanza can be used in combination with next month, fifth month or +8 months to go to the first day of the specified month. Instead of +1 month from what you're doing, you can use this code to get the first day of next month like this:

<?php $d = new DateTime( '2010-01-31' ); $d->modify( 'first day of next month' ); echo $d->format( 'F' ), "\n"; ?> 

This script will correctly output February. The following things happen when PHP processes this first day of next month stanza:

  1. next month increases the month number (originally 1) by one. This makes the date 2010-02-31.

  2. first day of sets the day number to 1, resulting in the date 2010-02-01.

like image 76
shamittomar Avatar answered Sep 25 '22 17:09

shamittomar


Here is another compact solution entirely using DateTime methods, modifying the object in-place without creating clones.

$dt = new DateTime('2012-01-31');  echo $dt->format('Y-m-d'), PHP_EOL;  $day = $dt->format('j'); $dt->modify('first day of +1 month'); $dt->modify('+' . (min($day, $dt->format('t')) - 1) . ' days');  echo $dt->format('Y-m-d'), PHP_EOL; 

It outputs:

2012-01-31 2012-02-29 
like image 39
Rudiger W. Avatar answered Sep 24 '22 17:09

Rudiger W.