Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does PHP date('m', strtotime('-1 months')) not work correctly for today? 07/31

I have a script that gets the current and last month in PHP like so:

$currentMonth = date('m');
//Expected:07
//Result:07
$lastMonth = date('m', strtotime('-1 months'));
//Expected:06
//Result:07

Today happens to be the 31 or end of the month of July. Is this result to be expected from PHP?

When using -31 days the result is as expected:

$lastMonth = date('m', strtotime('-31 days'));
//Expected:06
//Result:06
like image 360
Subie Avatar asked Jul 31 '15 16:07

Subie


People also ask

Why is Strtotime return false?

If the date string isn't understood by strtotime() then it will return false. When this happens you can try a few things to force strtotime() to parse the date correctly. Sometimes it's something as simple as swapping the slashes for dashes, which forces strtotime() to parse the date in a different way.

How does Strtotime work in 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.

How do you get a date from Strtotime?

Code for converting a string to dateTime$date = strtotime ( $input ); echo date ( 'd/M/Y h:i:s' , $date );


2 Answers

Here's a cleaner test case that doesn't expire:

<?php
$origin = mktime(18, 0, 0, 7, 31, 2015);
var_dump( date('r', $origin), date('r', strtotime('-1 months', $origin)) );
string(31) "Fri, 31 Jul 2015 18:00:00 +0200" 
string(31) "Wed, 01 Jul 2015 18:00:00 +0200"

I'm pretty sure it's a documentation issue, because the manual clearly states this (emphasis mine):

Relative month values are calculated based on the length of months that they pass through. An example would be "+2 month 2011-11-30", which would produce "2012-01-30". This is due to November being 30 days in length, and December being 31 days in length, producing a total of 61 days.

... and it's wrong.

PHP bug tracker has tons of dupes about this. They're all closed as not a bug. Here's a relevant comment from 2009 that explains it:

I agree that this is an annoying behaviour.

Also, the implementation is problematic. Basically if you use '+1 month' it takes the month number, adds 1 and parses result as a new date.

If you use '+1 month' on the first of the month, it sets the date to the next first of the month.

This behaviour gives the impression, that php considers the length of a month, which is not true.

But if you use '+1 month' on the last day of a month, the result is unexpected as 2009-05-31 becomes 2009-06-31 which is an invalid date and then interpreted as 2009-07-01.

This should at least be mentioned in the documentation.

like image 57
Álvaro González Avatar answered Oct 25 '22 12:10

Álvaro González


You can do this way

$d = new DateTime(); 
$currentMonth = $d->format('m');
//Expected:07
//Result:07
print $currentMonth;

$d->modify('first day of previous month');
print "<br/>";
$lastMonth = $d->format('m'); 
//Expected:06
//Result:06
print $lastMonth;

DEMO: http://codepad.viper-7.com/kokWi8

like image 38
Always Sunny Avatar answered Oct 25 '22 13:10

Always Sunny