15

This was working fine yesterday with no changes to the code.

echo date("M", strtotime("-3 month", time()) );
echo date("M", strtotime("-2 month", time()) );
echo date("M", strtotime("-1 month", time()) );
echo date("M", time());

The output it was producing yesterday was as you would expect- i.e. Apr, May, Jun, Jul

Today it echoes May May Jul Jul

Any ideas?

Thanks in advance.

6 Answers6

16

It might be related to bug #44073

You could try with something like this :

echo date("M", strtotime("-3 month", strtotime(date("F") . "1")) ) . "\n";
echo date("M", strtotime("-2 month", strtotime(date("F") . "1")) ) . "\n";
echo date("M", strtotime("-1 month", strtotime(date("F") . "1")) ) . "\n";
echo date("M", time()) . "\n";

(Solution found in the comments section of strtotime ; direct link)

And the output :

Apr
May
Jun
Jul

Kind of "cheating" with the date format and month's name and all that...

Pascal MARTIN
  • 395,085
  • 80
  • 655
  • 663
11

Gorden correctly identified the issue, but I wanted to give another solution that was helpful and not as technical. Just use "first day of" or "last day of" in your strtotime. Ex, these following examples overcome the issue on a 31st of a month:

// Today is May 31st
//All the following return 2012-04-30
echo date('Y-m-d', strtotime("last day of -1 month"));
echo date('Y-m-d', strtotime("last day of last month"));
echo date_create("last day of -1 month")->format('Y-m-d'); 

// All the following return 2012-04-01
echo date('Y-m-d', strtotime("first day of -1 month")); 
echo date('Y-m-d', strtotime("first day of last month"));
echo date_create("first day of -1 month")->format('Y-m-d');
SeanDowney
  • 17,368
  • 20
  • 81
  • 90
5

Try this instead of strtotime:

mktime(0, (date("n") - 3 + 12) % 12, 1)

The idea is to take the current month number (date("n")), substract the number of months from it you want (here -3), add 12 to it and then get modulo 12.

Gumbo
  • 643,351
  • 109
  • 780
  • 844
4

This is known and expected behavior. The reason for this is that a month is a relative date with no fixed length. From http://www.gnu.org/software/tar/manual/html_node/Relative-items-in-date-strings.html#SEC120

The unit of time displacement may be selected by the string ‘year’ or ‘month’ for moving by whole years or months. These are fuzzy units, as years and months are not all of equal duration. More precise units are ‘fortnight’ which is worth 14 days, ‘week’ worth 7 days, ‘day’ worth 24 hours, ‘hour’ worth 60 minutes, ‘minute’ or ‘min’ worth 60 seconds, and ‘second’ or ‘sec’ worth one second. An ‘s’ suffix on these units is accepted and ignored.

Consequently (emphasis mine)

The fuzz in units can cause problems with relative items. For example, ‘2003-07-31 -1 month’ might evaluate to 2003-07-01, because 2003-06-31 is an invalid date. To determine the previous month more reliably, you can ask for the month before the 15th of the current month. For example:

$ date -R
Thu, 31 Jul 2003 13:02:39 -0700
$ date --date='-1 month' +'Last month was %B?'
Last month was July?
$ date --date="$(date +%Y-%m-15) -1 month" +'Last month was %B!'
Last month was June!

The above could be expressed in PHP as

echo date('M', strtotime(date('Y-m-') . '15 -1 month'));

Also see the commments below http://bugs.php.net/bug.php?id=22486

Gordon
  • 312,688
  • 75
  • 539
  • 559
2

From PHP 5.3 (Ref: https://bugs.php.net/bug.php?id=44073) and higher you can do:

"first day of +1 month" or "first day of next month" or even "last day of next month"

Example:

$date = '2015-12-31';

echo date("Y-m-d", strtotime($date ."first day of previous month"));

Will produce: 2015-11-01 This does not calculate days on +30 days time basis.

Fakhruddin Ujjainwala
  • 2,493
  • 17
  • 26
0

a simple way could be to write it like this

echo date("M", strtotime("this year +3 months"));

or

echo date("M", strtotime("this month -3 months"));

depends what your using it for..

Chris Fazzio
  • 375
  • 1
  • 6
  • 16