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

Reply via email to