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
 [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

Add a Patch

Pull Requests

Add a Pull Request

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-2024 The PHP Group
All rights reserved.
Last updated: Tue May 21 14:01:33 2024 UTC