Bug #64414 [Com]: DateTime::createFromFormat() fails randomly when using microtime(true) as input
| From: | lunakid at gmail dot com | Date: | Tue, 02 Jun 2020 13:20:15 +0000 |
| Subject: | Bug #64414 [Com]: DateTime::createFromFormat() fails randomly when using microtime(true) as input | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-227277@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=64414&edit=1
ID: 64414
Comment by: lunakid at gmail dot com
Reported by: rewilliams at newtekemail dot com
Summary: DateTime::createFromFormat() fails randomly when
using microtime(true) as input
Status: Not a bug
Type: Bug
Package: Date/time related
Operating System: Red Hat 6.2; OS X 10.7.5
PHP Version: 5.4.12
Block user comment: N
Private report: N
New Comment:
Acknowledging that it's indeed one of the most embarrassing and "evil" surprises of
PHP, this is a float -> string conversion problem, not a date formatting bug. A float
should've always consistently had a fractional part, even if the value "seems to be"
integer (".0"), but it doesn't.
(As with many other "handy features" like magic quotes, registering globals, safe mode
etc., short-term practical reasons have historically drove design decisions: PHP was never really
aspired to be a "serious" language (at least before v5), so random historical cruft's
still causing headache accordingly. As to fixing it (assuming willingness solely for the thought
experiment): even though there have been lots of bigger breaking changes in the past to undo
previous decisions, this behavior may be more difficult to cleanly deprecate, and silent value
changes could even cause more subtle problems than this existing one. I'd personally still bite
the bullet and do it anyway, though...)
Previous Comments:
------------------------------------------------------------------------
[2020-01-27 17:37:08] nolife at gmail dot com
The response and "not a bug" declaration is shameful for the entire PHP project.
microtime() is a PHP internal routine
createFromFormat() is a PHP internal routine
If this is not a bug, nothing in the world ever has been a bug.
This is causing millions of errors worlwide, every single PHP project that formats the timestamp
with milliseconds is having random errors whenever the float value doesn't have precision.
How on earth could this bug stay in PHP code for so many years ?
------------------------------------------------------------------------
[2013-03-13 20:51:51] salathe@php.net
This looks to be a case of Garbage In, Garbage Out [1]. Your apparent "random"
misbehaviour is caused when the string representation of the float returned from
microtime(true) does not match the format string provided as the first argument to
DateTime::createFromFormat(). Printing out the string value of the microtime that
fails clearly shows this [2].
I would recommend providing an appropriate string value in the
DateTime::createFromFormat() call, matching "U.u" format. For example, using
something like sprintf("%.6F", microtime(true)).
Unfortunately, though it would be nice, using the string return value from
microtime(), when called without the $get_as_float argument set to true, is
currently not an option [3].
[1] http://en.wikipedia.org/wiki/Garbage_in,_garbage_out
[2] https://gist.github.com/salathe/5155971
[3] https://bugs.php.net/bug.php?id=60089
------------------------------------------------------------------------
[2013-03-12 18:45:49] rewilliams at newtekemail dot com
Updated test script:
<?php
ini_set('display_errors', true);
ini_set('error_reporting', E_ALL | E_STRICT);
for ($i = 1; $i < 1e6; $i++) {
if ($i % 50000 == 0) echo $i . "\n";
$foo = \DateTime::createFromFormat('U.u', \microtime(true));
if (!($foo instanceof DateTime)) {
echo "It failed!\ni: $i\n";
var_dump($foo, DateTime::getLastErrors());
exit;
} //if
} //for
?>
I removed the else clause; it's unrelated and doesn't need to be there.
------------------------------------------------------------------------
[2013-03-12 18:41:30] rewilliams at newtekemail dot com
Description:
------------
I have available to me the following PHP versions:
* PHP 5.4.11 running on OS X 10.7.5
* PHP 5.3.15 (Suhosin) running on OS X 10.7.5 (Apple's install)
* PHP 5.3.9 running on Red Hat Enterprise Linux 6.2
I'm able to easily reproduce this on all versions.
Essentially, what's happening is that randomly,
DateTime::createFromFormat() will return false, with the error "Data
missing" as reported by DateTime::getLastErrors(). For testing purposes,
I'm calling it in a loop until I see failure or until one million
iterations have run. On 5.4.11, probably 60% of test runs fail, while it
fails more often on older versions. When it does fail, it seems to be
random how many iterations it gets through - sometimes, just a few thousand
iterations, other times, mid-way or all the way through.
Notably, in our production environment (running 5.4.11), which is where we
discovered this, we only make the method call one or two times over the
course of an average request.
The parameters I'm passing in my test code are the only ones with which
I've seen this failure. With, say, 'Y-m-d H:i:s' as a format string, it
works every time for me. Related, it doesn't appear to be the microtime()
call itself failing, as I've put that in a loop by itself and not observed
a failure.
Below is an example of the error that's produced when it fails. Note that
in this case, it failed on iteration number 913,371.
[...]
800000
850000
900000
It failed!
i: 913371
bool(false)
array(4) {
["warning_count"]=>
int(0)
["warnings"]=>
array(0) {
}
["error_count"]=>
int(1)
["errors"]=>
array(1) {
[10]=>
string(12) "Data missing"
}
}
Test script:
---------------
<?php
ini_set('display_errors', true);
ini_set('error_reporting', E_ALL | E_STRICT);
for ($i = 1; $i < 1e6; $i++) {
if ($i % 50000 == 0) echo $i . "\n";
$foo = \DateTime::createFromFormat('U.u', \microtime(true));
if (!($foo instanceof DateTime)) {
echo "It failed!\ni: $i\n";
var_dump($foo, DateTime::getLastErrors());
exit;
} else {
$foo->format('Y-m-d\TH:i:s.uP');
} //if-else
} //for
?>
Expected result:
----------------
The DateTime::createFromFormat() call should work every time when given valid
parameters.
Actual result:
--------------
The DateTime::createFromFormat() call should works almost every time when given
valid parameters, but fails randomly. The reported error is "Data missing".
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=64414&edit=1