Bug #64188 [NEW]: strtotime is 7 times slower for dates that end with Z instead of UTC
| From: | efbiaiinzinz at hotmail dot com | Date: | Mon, 11 Feb 2013 08:32:37 +0000 |
| Subject: | Bug #64188 [NEW]: strtotime is 7 times slower for dates that end with Z instead of UTC | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-176559@lists.php.net to get a copy of this message | ||
From: efbiaiinzinz at hotmail dot com
Operating system: Windows / Linux / All
PHP version: 5.4.11
Package: Performance problem
Bug Type: Bug
Bug description:strtotime is 7 times slower for dates that end with Z instead of UTC
Description:
------------
According to the date rules seen at http://en.wikipedia.org/wiki/ISO_8601 a
date
with ending Z should be considered UTC date.
UTC description also says that UTC date can be denoted with appending Z to
the
end: http://en.wikipedia.org/wiki/Coordinated_Universal_Time
PHP codebase does follow those rules, but does so suboptimally.
We have a codebase that parses in big GPS files from different sport
watches and
so far all bigger providers (garmin, polar, suunto) encode the time values
in
those files as 2013-01-01T12:00:00Z or 2013-01-01T12:00:00.000Z.
We noticed that for bigger files the parsing times were quite bad and most
time
was spent in strtotime so we started to experiment. Removing the Z part
resulted
in fast strtotime but wrong result (date was assumed to be local not UTC).
When
we tried to replace Z with UTC, parsing was correct and fast.
After looking at date parsing code in PHP 5.4.11 we noticed few things:
ext/date/lib/parse_date.c
const static timelib_tz_lookup_table* zone_search(const char *word, long
gmtoffset, int isdst)
...
if (strcasecmp("utc", word) == 0 || strcasecmp("gmt", word) == 0) {
return timelib_timezone_utc;
}
ext/date/lib/parse_date.c
static long timelib_get_zone(char **ptr, int *dst, timelib_time *t, int
*tz_not_found, const timelib_tzdb *tzdb, timelib_tz_get_wrapper
tz_wrapper)
...
/* If we have a TimeZone identifier to start with, use it */
if (strstr(tz_abbr, "/") || strcmp(tz_abbr, "UTC") == 0) {
ext/date/lib/parse_date.c
const static timelib_tz_lookup_table timelib_timezone_utc[] = {
{ "utc", 0, 0, "UTC" },
};
There are optimizations for cases when string contains UTC but no
optimizations
for another official UTC format that ends with Z.
We tested on PHP 5.4.11 and 5.3.21 on a windows machin plus on our
production
Linux server with PHP 5.3.20.
Test script:
---------------
<?php
ini_set('date.timezone', 'UTC');//make sure no warnings are shown
$br = isset($_SERVER['HTTP_USER_AGENT']) ? "<br />\r\n" :
"\r\n";
$times_z = $times_utc = array();
$time = time();
$counter = 50000;
for($i = 0; $i < $counter; $i++, $time++) {//Generate two arrays, one has
datetimes that end with Z and other has UTC endings
$date = date('Y-m-d\TH:i:s', $time);
$times_z []= $date . 'Z';
$times_utc []= $date . 'UTC';
}
for($start_z = microtime(true), $i = 0; $i < $counter; $i++) $tmp =
strtotime($times_z[$i]);
$dur_z = microtime(true) - $start_z;
for($start_u = microtime(true), $i = 0; $i < $counter; $i++) $tmp =
strtotime($times_utc[$i]);
$dur_u = microtime(true) - $start_u;
for($start_u2 = microtime(true), $i = 0; $i < $counter; $i++) $tmp =
strtotime(str_replace('Z', 'UTC', $times_utc[$i]));
$dur_u2 = microtime(true) - $start_u2;
echo 'Z took ' . number_format($dur_z, 4) . 's, UTC took ' .
number_format($dur_u, 4) . 's, Z with str_replace to UTC took ' .
number_format($dur_u2, 4) . 's' . $br;
if ($dur_z <= $dur_u) echo 'UTC format was ' . (number_format($dur_u /
$dur_z, 2)) . ' times slower than Z' . $br;
else echo 'Z format was ' . (number_format($dur_z / $dur_u, 2)) . ' times
slower than UTC' . $br;
Expected result:
----------------
I would expect to see UTC and Z versions having similar parsing times.
Actual result:
--------------
On windows with PHP 5.4.11, Z format parsing is 7 times slower than UTC
version,
using str_replace for all dates (Z => UTC) is 1.1 times slower than UTC
version.
On windows with PHP 5.3.21, Z format parsing is 6.1 times slower than UTC
version,
using str_replace for all dates (Z => UTC) is 1.1 times slower than UTC
version.
On Linux server with PHP 5.3.20 + APC, Z format parsing is 5 times slower
than UTC
version, using str_replace for all dates (Z => UTC) is 1.15 times slower
than UTC
version.
--
Edit bug report at https://bugs.php.net/bug.php?id=64188&edit=1
--
Try a snapshot (PHP 5.4): https://bugs.php.net/fix.php?id=64188&r=trysnapshot54
Try a snapshot (PHP 5.3): https://bugs.php.net/fix.php?id=64188&r=trysnapshot53
Try a snapshot (trunk): https://bugs.php.net/fix.php?id=64188&r=trysnapshottrunk
Fixed in SVN: https://bugs.php.net/fix.php?id=64188&r=fixed
Fixed in release: https://bugs.php.net/fix.php?id=64188&r=alreadyfixed
Need backtrace: https://bugs.php.net/fix.php?id=64188&r=needtrace
Need Reproduce Script: https://bugs.php.net/fix.php?id=64188&r=needscript
Try newer version: https://bugs.php.net/fix.php?id=64188&r=oldversion
Not developer issue: https://bugs.php.net/fix.php?id=64188&r=support
Expected behavior: https://bugs.php.net/fix.php?id=64188&r=notwrong
Not enough info: https://bugs.php.net/fix.php?id=64188&r=notenoughinfo
Submitted twice: https://bugs.php.net/fix.php?id=64188&r=submittedtwice
register_globals: https://bugs.php.net/fix.php?id=64188&r=globals
PHP 4 support discontinued: https://bugs.php.net/fix.php?id=64188&r=php4
Daylight Savings: https://bugs.php.net/fix.php?id=64188&r=dst
IIS Stability: https://bugs.php.net/fix.php?id=64188&r=isapi
Install GNU Sed: https://bugs.php.net/fix.php?id=64188&r=gnused
Floating point limitations: https://bugs.php.net/fix.php?id=64188&r=float
No Zend Extensions: https://bugs.php.net/fix.php?id=64188&r=nozend
MySQL Configuration Error: https://bugs.php.net/fix.php?id=64188&r=mysqlcfg