php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #64188 strtotime is 7 times slower for dates that end with Z instead of UTC
Submitted: 2013-02-11 08:32 UTC Modified: 2021-02-03 13:25 UTC
Votes:1
Avg. Score:3.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:0 (0.0%)
Same OS:1 (100.0%)
From: efbiaiinzinz at hotmail dot com Assigned: cmb (profile)
Status: Not a bug Package: Performance problem
PHP Version: 5.4.11 OS: Windows / Linux / All
Private report: No CVE-ID: None
 [2013-02-11 08:32 UTC] efbiaiinzinz at hotmail dot com
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.

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2021-02-03 13:25 UTC] cmb@php.net
-Status: Open +Status: Not a bug -Assigned To: +Assigned To: cmb
 [2021-02-03 13:25 UTC] cmb@php.net
If this is still relevant, please report it upstream to
<https://github.com/derickr/timelib>.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sun Apr 28 13:01:29 2024 UTC