php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #71255 Error in strtotime last day of month
Submitted: 2015-12-31 11:56 UTC Modified: 2015-12-31 23:31 UTC
From: ruben at solunapilates dot es Assigned:
Status: Not a bug Package: Date/time related
PHP Version: 5.5.30 OS: Ubuntu 14.04
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: ruben at solunapilates dot es
New email:
PHP Version: OS:

 

 [2015-12-31 11:56 UTC] ruben at solunapilates dot es
Description:
------------
In day 31 of December, the function date('F',strtotime('- 1 month')); returns "December" instead November. Happens all months

Test script:
---------------
$today=date('F',strtotime('- 1 month'));

print($today);



Expected result:
----------------
November

Actual result:
--------------
December

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-12-31 14:10 UTC] bwoebi@php.net
-Status: Open +Status: Not a bug
 [2015-12-31 14:10 UTC] bwoebi@php.net
That just happens on months with more days than previous month on the last day.

December 31 - 1 month = November 31 => December 1

Better try date('F',strtotime('first day of last month')), which will give you what you expect.
 [2015-12-31 19:13 UTC] ruben at solunapilates dot es
Hi, Yes, your workaround works, but the right behaviour must be "if 31/11 doesn't exist, show a month before" because we are trying to get "a month before" (-1 month), is not?
 [2015-12-31 20:29 UTC] a at b dot c dot de
By that logic, date('Y', strtotime('-1 year', strtotime('2016-02-29'))) should return 2012 because 2015-02-29 doesn't exist.
 [2015-12-31 23:31 UTC] rasmus@php.net
Of course not, 2016/02/29 - a year would be 2015/03/01. This is how UNIX date math works. You can try the original issue from your Linux shell prompt:

% date --date='-1 month' +'Last month was %B?'
Last month was December?

Or in sqlite:

sqlite> select datetime('2015-12-31', '-1 month');
2015-12-01 00:00:00

See this for some extra background:
http://www.gnu.org/software/tar/manual/html_node/Relative-items-in-date-strings.html#SEC120

PHP is consistent with GNU tools and the many other tools using this standard approach. In the end there is no right answer when you are subtracting a fuzzy concept such as a year or a month.

Take this, for example:

php > echo date('Y/m/d', strtotime('-1 month', strtotime('2015/12/31')));
2015/12/01
php > echo date('Y/m/d', strtotime('-1 month', strtotime('2015/12/30')));
2015/11/30

By your logic these should both return the same day? That doesn't make much sense. Having 31-n == 30-n would make doing math on timestamps and comparing results really difficult if 31-n was not greater than 30-n. UNIX chooses mathematical consistency at the timestamp level. Mapping these timestamps to a display date is where things get interesting and you have to take this into account when you apply fuzzy concepts like months and years to timestamps.
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Sat May 03 15:01:28 2025 UTC