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