One of the fringe benefits of open sourcing an existing code base is that you have an opportunity to set error_reporting to E_ALL | E_STRICT, or perhaps rather to 2147483647. When you do that you find small problems with your code base you missed the first time you sloppily wrote it.
In my case, I noticed that date() was throwing strict errors. For example
error_reporting(E_ALL | E_STRICT);
ini_set('date.timezone',false);
echo date('c');
shows you
I’m sure if you’re Derick, you are intimate with date()ing, but I had forgotten about this wasted guess_timezone() sys call and the suppressed strict error (which still takes time in PHP 5).
I sent an e-mail with this bug, along with the one line fix to the php.ini, to site operations…and promptly forgot about it. That is until the ticket was sent back with the message that it needed to be “tested in dev and stage before making it to production.”
(The younger, less-tolerant terry would have blown a fuse at this point.) The older, jaded terry simply became curious about what the costs of date() really are.
Benchmarking
The last time I did synthetic benchmarking was week 1 at Tagged where I wrote a harness to compare sqlrelay vs. two home grown connection pools. Not happy with PEAR’s Benchmark_Iterate, I figured it was time to write a benchmarking suite again.
// Bootstrap this without framework
include('timer.php');
include('iterate.php');
//mimic production
$error_level = error_reporting(0);
// {{{ date()
ini_set('date.timezone',false);
$b1 = new tgif_benchmark_iterate(true);
$b1->run(10000, 'date', 'c');
$b1->description = 'date("c")';
// }}}
// {{{ date() + date.timezone
ini_set('date.timezone','America/Los_Angeles');
$b2 = new tgif_benchmark_iterate(true);
$b2->run(10000, 'date', 'c');
$b2->description = 'date("c") + date.timezone';
// }}}
// {{{ iterate date() + ini_set
//date_default_timezone_set('');
ini_set('date.timezone',false);
function ini_and_date() {
ini_set('date.timezone','America/Los_Angeles');
date('c');
}
$b4 = new tgif_benchmark_iterate(true);
$b4->run(10000, 'ini_and_date');
$b4->description = 'iterate date("c") + ini_set';
// }}}
// {{{ date() + date_default_timezone_set
ini_set('date.timezone',false);
date_default_timezone_set('America/Los_Angeles');
$b3 = new tgif_benchmark_iterate(true);
$b3->run(10000, 'date', 'c');
$b3->description = 'date("c") + date_default_timezone_set()';
// }}}
// {{{ iterate date() + date_default_timezone_set
//date_default_timezone_set('');
ini_set('date.timezone',false);
function set_and_date() {
date_default_timezone_set('America/Los_Angeles');
date('c');
}
$b5 = new tgif_benchmark_iterate(true);
$b5->run(10000, 'set_and_date');
$b5->description = 'iterate date("c") + date_default_timezone_set';
// }}}
echo tgif_benchmark_iterate::format($b1->compare($b2,$b3,$b4,$b5));
// restore
error_reporting($error_level);
(Here are timer.php and iterate.php. If there are major bugs, I apologize, I hacked it together in bed last night.)
Results
I should have really rebuilt my dev install not to have xdebug, inclued, and other debugging crap here. In any case, here is the result when performed on my MacBook Pro:
| mark | wall time | resource time |
|---|---|---|
| date(“c”) | 0.000043s | 0.000044s |
| date(“c”) + date.timezone | 5.53x | 5.60x |
| date(“c”) + date_default_timezone_set() | 6.79x | 6.96x |
| iterate date(“c”) + ini_set | 3.30x | 3.37x |
| iterate date(“c”) + date_default_timezone_set | 3.45x | 3.55x |
Yeah, we’re talking about microseconds here, but as you can see, even if you set the default timezone on every request and only call date() once on average, you’re still much better off with a userspace ini_set or date_default_timezone_set than with doing nothing. That’ll add up if some idiot programmer has date() caught in a tight loop to build a calendar or something—don’t laugh, I’ve seen this. And since doing it in user-space doesn’t require another bounced trouble ticket, I promptly did just that.
We’ve been running that way for a couple weeks now.
No one has noticed yet.













