# question about backward-compatibility break/bug in php 5.2.6

- Thread: https://externals.io/message/39250
- Original archive: https://news-web.php.net/php.internals/39250
- Started by Jack Steadman on 2008-07-23T19:49:10+00:00
- Messages: 10
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #39250 — Jack Steadman — 2008-07-23T19:49:10+00:00

URL: https://externals.io/message/39250#39250

Hello all,

Last week I submitted a bug report on the issue described below.  The
response (also below) was that this is not a bug.  I fail to see how it
could *not* be a bug given that strtotime is parsing an invalid date
into a seemingly-arbitrary and definitely-meaningless number, rather
than returning false as it is supposed to.  Can someone explain to me
why this is "intended" behavior?  We do rely on strtotime returning
false on invalid dates, and this behavior changed between 5.2.5 and
5.2.6.  Do we need to update our code to check for this arbitrary
negative integer?  I would prefer not to do that.

Thanks,
Jack Steadman
Smarter Travel Media LLC

--------------------------------------------------
Operating system: RHEL 4/5
PHP version:      5.2.6
PHP Bug Type:     Date/time related
Bug description:  strtotime parses 0000-00-00 00:00:00 as valid date

Description:
------------
MySQL uses '0000-00-00 00:00:00' as a default value for non-null
datetime
fields.  Until 5.2.6, strtotime correctly returned false (or -1 before
5.1)
when passed this value - it's not a valid date/time.

5.2.6 returns '-62169966000' which is not useful.


Reproduce code:
---------------
<?php echo (int)strtotime('0000-00-00 00:00:00');


Expected result:
----------------
Should print 0.


Actual result:
--------------
Actually prints -62169966000.


[18 Jul 7:25am UTC] derick@php.net

Please do not submit the same bug more than once. An existing
bug report already describes this very problem. Even if you feel
that your issue is somewhat different, the resolution is likely
to be the same. 

Thank you for your interest in PHP.

http://bugs.php.net/bug.php?id=42971
http://bugs.php.net/bug.php?id=44453

This is not a bug. MySQL is being silly to use this string as a default
value. In PHP 5.3 you can now detect this however, by using
date_parse_from_format( "Y-m-d H:i:s"); and then check the contents of
 `date_get_last_errors()`.

[18 Jul 1:31pm UTC] jack+phpdotnet at smartertravelmedia dot com

First of all, those previously-reported bugs are with the DateTime
class, not strtotime.  If DateTime uses strtotime or its underlying
implementation, that's not for me to know.  I searched the bug database
before submitting this report and did not find the two you mentioned. 
Your "similar bugs" prompt didn't flag them either.

Second, how is this not a bug?  strtotime's manual page says, "Returns a
timestamp on success, `FALSE` otherwise."  The string of zeroes that mysql
uses is NOT a valid datetime string, so how is strtotime "successfully"
parsing it into a random negative number?  That's aside from the fact
that this is a behavior *change* from 5.2.5 to 5.2.6 - that alone makes
it a problem.

Third, you can think mysql is silly for using this as a default all you
want, but they've been doing it since at least version 3.23 if not
before.  Just because you don't agree with it doesn't mean PHP shouldn't
handle it as advertised - namely to return false if an invalid date/time
string is passed to strtotime.

---

## #39254 — Tomas Kuliavas — 2008-07-24T05:34:02+00:00

URL: https://externals.io/message/39250#39254 · In reply to: #39250

> Hello all,
>
> Last week I submitted a bug report on the issue described below.  The
> response (also below) was that this is not a bug.  I fail to see how it
> could *not* be a bug given that strtotime is parsing an invalid date
> into a seemingly-arbitrary and definitely-meaningless number, rather
> than returning false as it is supposed to.  Can someone explain to me
> why this is "intended" behavior?  We do rely on strtotime returning
> false on invalid dates, and this behavior changed between 5.2.5 and
> 5.2.6.  Do we need to update our code to check for this arbitrary
> negative integer?  I would prefer not to do that.

Date is not invalid. Some diety was born at -62169966000 Unixtime.

-- 
Tomas

---

## #39258 — Christian Seiler — 2008-07-24T08:50:25+00:00

URL: https://externals.io/message/39250#39258 · In reply to: #39250

Hi,

> Last week I submitted a bug report on the issue described below.  The
> response (also below) was that this is not a bug.  I fail to see how it
> could *not* be a bug given that strtotime is parsing an invalid date
> into a seemingly-arbitrary and definitely-meaningless number,

 `strtotime()` has always accepted month and day numbers 0 in order to
express "last month of the previos year" and "last day of the previous
month". Take:

var_dump (date ('Y-m-d H:i:s', strtotime ('2008-00-01 12:00:00')));

This gives:

string(19) "2007-12-01 12:00:00"

Here, the 00 is interpreted as "month before January" and thus December
of the previous year. Then, take:

var_dump (date ('Y-m-d H:i:s', strtotime ('2008-02-00 12:00:00')));

This gives:

string(19) "2008-01-31 12:00:00"

Here, the 00 is interpreted as "day before the first day of that month"
and thus the 31st of January.

Take both together, you get:

var_dump (date ('Y-m-d H:i:s', strtotime ('2008-00-00 12:00:00')));
string(19) "2007-11-30 12:00:00"

Now, take the date '0000-01-01'. This is a valid date according to ISO
8601 and simply means the 1st of January in 1 BC (but according to a
proleptic gregorian calendar, because ISO 8601 defines it as that). So
'0000-00-00' is actually the 30th of November of 2 BC (proleptic
gregorian calendar).

Now, the return value of `strtotime()` is actually defined as the number
of seconds since the 1st of January 1970, 00:00:00 UTC. If you add
-62169966000 seconds to that date, you get the 30th of November 2 BC
(proleptic gregorian calendar) at 00:00:00 of your time zone.

Also, it is not a regression. On my 32bit CPU, `strtotime()` still returns
false for your date since a 32bit integer cannot represent such a large
number and thus `strtotime()` can't return a valid timestamp. But on a
64bit CPU, integers are large enough to hold that number and `strtotime()`
can return a valid timestamp. If you compile a very old PHP version on a
64bit system, it will yield the same results.

As somebody already commented in the bug reports: It's not a bug.

You can write yourself a wrapper if you want to catch that specific date:

function my_strtotime($str, $ts = null) {
   if ($ts === null) $ts = time ();
   return $str == '0000-00-00 00:00:00' ? false : strtotime ($str, $ts);
}

Regards,
Christian

---

## #39268 — Jack Steadman — 2008-07-24T13:40:09+00:00

URL: https://externals.io/message/39250#39268 · In reply to: #39258

Thank you for taking the time to explain this to me.  A couple more
points below:

> `strtotime()` has always accepted month and day numbers 0 in order to
> express "last month of the previos year" and "last day of the previous
> month". Take:

So my biggest issue with this is that it's exception-case behavior,
treating truly invalid dates as valid dates for no obvious reason.  Who
needs this functionality?  Why is it even a good idea?

A close second is that this behavior is completely undocumented.
http://us.php.net/strtotime states that the time argument to strtotime
is "The string to parse, according to the GNU > Date Input Formats
syntax" and that false is returned on failure.  GNU date formats do NOT
allow for zero months and days (see
http://www.gnu.org/software/tar/manual/html_node/Calendar-date-items.htm
l#SEC116).  No official mention is made of the exception case that you
describe.  The closest the docs come is a user comment on the strtotime
page from June 19 of this year (perhaps someone who upgraded to 5.2.6
and found this behavior for the first time?) warning other users that
2008-00-14 is interpreted as 2007-12-14.


> Also, it is not a regression. On my 32bit CPU, `strtotime()` 
> still returns false for your date since a 32bit integer 
> cannot represent such a large number and thus `strtotime()` 
> can't return a valid timestamp. But on a 64bit CPU, 
> integers are large enough to hold that number and `strtotime()`
> can return a valid timestamp. If you compile a very old PHP 
> version on a 64bit system, it will yield the same results.

This is not actually the case.  Take one of our machines (first part of
php -i included here):

System => Linux wollaston 2.6.9-55.0.9.ELsmp #1 SMP Tue Sep 25 02:16:15
EDT 2007 x86_64
Build Date => Jul 22 2008 11:41:54
Configure Command =>  './configure'  '--with-mysql=/usr/lib64'
'--with-gettext' '--with-openssl' '--enable-ftp'
'--with-zlib-dir=/usr/lib64' '--enable-pcntl' '--with-pdo-mysql=/usr'
'--without-sqlite' '--without-pdo-sqlite' '--with-apac
he=../apache_1.3.41' '--with-curl' '--enable-cli'
Server API => Command Line Interface
Virtual Directory Support => disabled
Configuration File (php.ini) Path => /usr/local/lib
Loaded Configuration File => /usr/local/Zend/Platform/etc/php.ini
PHP API => 20041225
PHP Extension => 20060613
Zend Extension => 220060519
Debug Build => no
Thread Safety => disabled
Zend Memory Manager => enabled
IPv6 Support => enabled
Registered PHP Streams => php, file, data, http, ftp, compress.zlib,
https, ftps  
Registered Stream Socket Transports => tcp, udp, unix, udg, ssl, sslv3,
sslv2, tls
Registered Stream Filters => string.rot13, string.toupper,
string.tolower, string.strip_tags, convert.*, consumed, convert.iconv.*,
zlib.*

This program makes use of the Zend Scripting Language Engine:
Zend Engine v2.2.0, Copyright (c) 1998-2007 Zend Technologies
    with Zend Extension Manager v1.2.0, Copyright (c) 2003-2006, by Zend
Technologies
    with Zend Optimizer v3.2.8, Copyright (c) 1998-2007, by Zend
Technologies
    with jobqueue_client wrapper v1.0, Copyright (c) 2004-2007, by Zend
Technologies
    with DISABLED Zend Download Server v1.0.6, Copyright (c) 2003-2005,
by Zend Technologies
    with DISABLED Zend Platform v3.0.3, Copyright (c) 1999-2007, by The
Zend Platform presently supports only Apache, ISAPI and FastCGI SAPIs
    with Zend Debugger v5.2.8, Copyright (c) 1999-2007, by Zend
Technologies
    with gd wrapper v1.0, Copyright (c) 2004-2007, by Zend Technologies
    with mod_cluster wrapper v1.0, Copyright (c) 2004-2007, by Zend
Technologies


This 64-bit machine is running 5.2.5 and returns false on the all-zero
datetime string.  It was upgraded last week to 5.2.6 and started
returning the large negative integer.  Downgrading back to 5.2.5 fixed
the problem and it again returns false.  Aside from that, the original
tests I ran and included with the bug report were both run on 64-bit
machines, one running 5.2.5 and the other (the machine whose info is
above) running 5.2.6.  In fact we don't have any 32-bit machines for me
to even try this out on.

*Something* changed in date handling between 5.2.5 and 5.2.6.  Whether
you perpetuate the exception case or not, it *is* a regression.

Jack

---

## #39269 — Christian Seiler — 2008-07-24T14:35:09+00:00

URL: https://externals.io/message/39250#39269 · In reply to: #39268

Hi!

> This 64-bit machine is running 5.2.5 and returns false on the all-zero
> datetime string.  It was upgraded last week to 5.2.6 and started
> returning the large negative integer.

Ah, yes, the change responsible is the following:

<http://cvs.php.net/viewvc.cgi/php-src/ext/date/lib/timelib.h?r1=1.10.2.11.2.4&r2=1.10.2.11.2.5&pathrev=PHP_5_2>

It fixes bug #44209 <http://bugs.php.net/bug.php?id=44209>. timelib.h
didn't include limits.h and thus always defined LONG_MAX / LONG_MIN to
the 32bit values for longs and thus the check in timelib.c for LONG_MIN
failed in 5.2.5 for your timestamp. But as 5.2.6 fixed that (LONG_MIN
from limits.h used when present), your timestamp became valid and
 `strtotime()` returned it.

Or to put it that way: The current behaviour of PHP 5.2.6 is the
expected behaviour (at least what reading the source tells about the
author's intentions) and it was broken before.

As to whether it's a good idea that `strtotime()` accepts invalid dates,
I'll stay out of that discussion.

Regards,
Christian

---

## #39272 — Jack Steadman — 2008-07-24T15:09:56+00:00

URL: https://externals.io/message/39250#39272 · In reply to: #39269

> Ah, yes, the change responsible is the following:
> 
> <http://cvs.php.net/viewvc.cgi/php-src/ext/date/lib/timelib.h?
> r1=1.10.2.11.2.4&r2=1.10.2.11.2.5&pathrev=PHP_5_2>
> 
> It fixes bug #44209 <http://bugs.php.net/bug.php?id=44209>. 

OK, thanks, it's good to understand the change in behavior.


> Or to put it that way: The current behaviour of PHP 5.2.6 is the
> expected behaviour (at least what reading the source tells about the
> author's intentions) and it was broken before.
> 
> As to whether it's a good idea that `strtotime()` accepts invalid dates,
> I'll stay out of that discussion.

If this is the way it's always been (accepting zero month and day values
as you described earlier), then I suspect that you'll be reluctant to
change behavior without significant thought (and of course, I wouldn't
expect otherwise, even though I've expressed my disagreement with the
current behavior).

What's the best way to get this fully documented?  Should I submit a new
bug report relating to the documentation, rather than a PHP bug?

Jack

---

## #39273 — Zach Shepherd — 2008-07-24T15:22:00+00:00

URL: https://externals.io/message/39250#39273 · In reply to: #39272

I'm not sure that there's any problem with the documentation (although it
wouldn't hurt to mention it in the comments). What is it about "0000-00-00
00:00:00" that makes it an invalid date? (See Christian's explanation)

Zach

On Thu, Jul 24, 2008 at 11:09 AM, Jack Steadman <jack@smartertravelmedia.com>
wrote:

>
> > […]
>
> OK, thanks, it's good to understand the change in behavior.
>
>
> > […]
>
> If this is the way it's always been (accepting zero month and day values
> as you described earlier), then I suspect that you'll be reluctant to
> change behavior without significant thought (and of course, I wouldn't
> expect otherwise, even though I've expressed my disagreement with the
> current behavior).
>
> What's the best way to get this fully documented?  Should I submit a new
> bug report relating to the documentation, rather than a PHP bug?
>
> Jack

---

## #39275 — Jack Steadman — 2008-07-24T15:30:57+00:00

URL: https://externals.io/message/39250#39275 · In reply to: #39273

> I'm not sure that there's any problem with the documentation 
> (although it wouldn't hurt to mention it in the comments). 
> What is it about "0000-00-00 00:00:00" that makes it an 
> invalid date? (See Christian's explanation)

Zero values for month and day are NOT valid.  PHP treats them as valid,
but according to GNU (on whose requirements strtotime's parsing is
based, according to the docs), month values must be in the range of 1-12
and day values must be 1-31.

Come to think of it, I wonder how PHP handles something like
'2008-06-31' - does it treat that as July 1?  Or does it call it an
invalid date?  Seems like the same sort of behavior - should be
considered invalid, but I'm betting that PHP handles it transparently.

The upshot is that we can't actually rely on strtotime to determine
whether a string is a valid date/time.  The docs don't ever explicitly
say that the date strings themselves are checked for validity, but
returning false on "failure" implies to me that it will return false if
it can't get a *valid* date out of the string.

Jack

---

## #39278 — Jordan Wambaugh — 2008-07-24T18:16:15+00:00

URL: https://externals.io/message/39250#39278 · In reply to: #39275

> The upshot is that we can't actually rely on strtotime to determine
> whether a string is a valid date/time.  The docs don't ever explicitly
> say that the date strings themselves are checked for validity, but
> returning false on "failure" implies to me that it will return false  
> if
> it can't get a *valid* date out of the string.

-62169966000 is a valid date. Perhaps instead of checking if strtotime  
returns a false for your error condition, check if it returns a value  
< 1.


--
Jordan CM Wambaugh
Lead Software Engineer
Forrent Media Solutions
jordan.wambaugh@forrent.com

---

## #39322 — Derick Rethans — 2008-07-25T11:12:11+00:00

URL: https://externals.io/message/39250#39322 · In reply to: #39268

> Thank you for taking the time to explain this to me.  A couple more
> points below:
> 
> > […]
> 
> So my biggest issue with this is that it's exception-case behavior,
> treating truly invalid dates as valid dates for no obvious reason.  Who
> needs this functionality?  Why is it even a good idea?

It's nice to find the last day of next month. 

> A close second is that this behavior is completely undocumented.
> http://us.php.net/strtotime states that the time argument to strtotime
> is "The string to parse, according to the GNU > Date Input Formats
> syntax" and that false is returned on failure.  GNU date formats do NOT
> allow for zero months and days (see
> http://www.gnu.org/software/tar/manual/html_node/Calendar-date-items.htm
> l#SEC116).  No official mention is made of the exception case that you
> describe.  The closest the docs come is a user comment on the strtotime
> page from June 19 of this year (perhaps someone who upgraded to 5.2.6
> and found this behavior for the first time?) warning other users that
> 2008-00-14 is interpreted as 2007-12-14.

Yes, the documentation is broken. I'm working on fixing that.

> This is not actually the case.  Take one of our machines (first part of
> php -i included here):

<snip>

> This 64-bit machine is running 5.2.5 and returns false on the all-zero
> datetime string.  It was upgraded last week to 5.2.6 and started
> returning the large negative integer.

<snip>

> *Something* changed in date handling between 5.2.5 and 5.2.6.  Whether
> you perpetuate the exception case or not, it *is* a regression.

Yes, because there was a regression in 5.2.[45]:

php-5.2.6$ sapi/cli/php -n -r 'var_dump( strtotime( "0000-00-00 00:00" ) );'
int(-62169987600)

php-5.2.5$ sapi/cli/php -n -r 'var_dump( strtotime( "0000-00-00 00:00" ) );'
bool(false)

php-5.2.4$ sapi/cli/php -n -r 'var_dump( strtotime( "0000-00-00 00:00" ) );'
bool(false)

even in PHP 5.1 it doesn't return false (although it's incorrect):

$ php-5.1dev -n -r 'var_dump( strtotime( "0000-00-00 00:00" ) );' 
int(943916400)

and *even* on 4.3.9:

$ php-4.3.9 -n -r 'var_dump( strtotime( "0000-00-00 00:00" ) );'
int(943916400)

regards,
Derick

-- 
HEAD before 5_3!: http://tinyurl.com/6d2esb
http://derickrethans.nl | http://ezcomponents.org | http://xdebug.org
