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
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: efbiaiinzinz at hotmail dot com
New email:
PHP Version: OS:

 

 [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

Pull Requests

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: Sat Dec 21 18:01:29 2024 UTC