|
Smarty
WARNING: All discussion is moving to https://reddit.com/r/smarty, please go there! This forum will be closing soon. |
|
View previous topic :: View next topic |
Author |
Message |
Loki Smarty Rookie
Joined: 13 Jan 2011 Posts: 30
|
Posted: Fri Jan 14, 2011 9:37 pm Post subject: smarty_make_timestamp can be faser |
|
|
In file smarty/plugins/shared.make_timestamp.php following function:
Code: |
function smarty_make_timestamp($string)
{
if(empty($string)) {
// use "now":
return time();
} elseif ($string instanceof DateTime) {
return $string->getTimestamp();
} elseif (preg_match('/^\d{14}$/', $string)) {
// it is mysql timestamp format of YYYYMMDDHHMMSS?
return mktime(substr($string, 8, 2),substr($string, 10, 2),substr($string, 12, 2),
substr($string, 4, 2),substr($string, 6, 2),substr($string, 0, 4));
} elseif (is_numeric($string)) {
// it is a numeric string, we handle it as timestamp
return (int)$string;
} else {
// strtotime should handle it
$time = strtotime($string);
if ($time == -1 || $time === false) {
// strtotime() was not able to parse $string, use "now":
return time();
}
return $time;
}
} |
For each call is executed a slow function preg_match (even for timestamp).
I propose to change it as follows
Code: |
function smarty_make_timestamp($string)
{
if(empty($string)) {
// use "now":
return time();
} elseif ($string instanceof DateTime) {
return $string->getTimestamp();
} elseif (is_numeric($string)) {
if (strlen($string)==14) {
// it is mysql timestamp format of YYYYMMDDHHMMSS?
return mktime(substr($string, 8, 2),substr($string, 10, 2),substr($string, 12, 2),
substr($string, 4, 2),substr($string, 6, 2),substr($string, 0, 4));
} else {
// it is a numeric string, we handle it as timestamp
return (int)$string;
}
} else {
// strtotime should handle it
$time = strtotime($string);
if ($time == -1 || $time === false) {
// strtotime() was not able to parse $string, use "now":
return time();
}
return $time;
}
}
|
|
|
Back to top |
|
mohrt Administrator
Joined: 16 Apr 2003 Posts: 7368 Location: Lincoln Nebraska, USA
|
Posted: Sun Jan 16, 2011 4:35 pm Post subject: |
|
|
From the PHP manual for is_numeric:
Quote: | Finds whether the given variable is numeric. Numeric strings consist of optional sign, any number of digits, optional decimal part and optional exponential part. Thus +0123.45e6 is a valid numeric value. Hexadecimal notation (0xFF) is allowed too but only without sign, decimal and exponential part. |
So your suggested code could possibly get a really messed up "mysql" datestamp. The preg guarantees exactly 14 digit chars. |
|
Back to top |
|
Loki Smarty Rookie
Joined: 13 Jan 2011 Posts: 30
|
Posted: Sun Jan 16, 2011 5:46 pm Post subject: |
|
|
You right. But it's possible to replace
Code: |
} elseif (is_numeric($string)) {
|
by
Code: | } elseif (is_int($string)) { |
or
Code: | } elseif (intval($string)) { |
|
|
Back to top |
|
mohrt Administrator
Joined: 16 Apr 2003 Posts: 7368 Location: Lincoln Nebraska, USA
|
Posted: Sun Jan 16, 2011 6:02 pm Post subject: |
|
|
afaik is_int() tests if a variable type is int, not if a string value is all number characters. is_numeric() tests if a string type is numeric in format, but accepts other characters than numbers. We need to be sure a string has a format of 14 number characters. |
|
Back to top |
|
rodneyrehm Administrator
Joined: 30 Mar 2007 Posts: 674 Location: Germany, border to Switzerland
|
Posted: Sun Jan 16, 2011 8:07 pm Post subject: |
|
|
how about this?
Code: | if (is_numeric($string)) {
if (strlen($string) == 14) {
return mktime(
substr($string, 8, 2),
substr($string, 10, 2),
substr($string, 12, 2),
substr($string, 4, 2),
substr($string, 6, 2),
substr($string, 0, 4)
);
} else {
return (int) $string;
}
} |
|
|
Back to top |
|
mohrt Administrator
Joined: 16 Apr 2003 Posts: 7368 Location: Lincoln Nebraska, USA
|
Posted: Sun Jan 16, 2011 8:43 pm Post subject: |
|
|
already answered that, read up two posts. |
|
Back to top |
|
Loki Smarty Rookie
Joined: 13 Jan 2011 Posts: 30
|
Posted: Mon Jan 17, 2011 8:53 pm Post subject: |
|
|
Code: | } elseif (intval($string)>0 && strlen($string)==14) { |
i understood that preg it's easiest way but, unfortunately, it's too slow |
|
Back to top |
|
rodneyrehm Administrator
Joined: 30 Mar 2007 Posts: 674 Location: Germany, border to Switzerland
|
Posted: Mon Jan 17, 2011 8:59 pm Post subject: |
|
|
Loki wrote: | Code: | } elseif (intval($string)>0 && strlen($string)==14) { |
i understood that preg it's easiest way but, unfortunately, it's too slow |
that test would fail these:
Code: | $string = "3.141500000000";
$string = "3e000000000001";
// … |
|
|
Back to top |
|
mohrt Administrator
Joined: 16 Apr 2003 Posts: 7368 Location: Lincoln Nebraska, USA
|
Posted: Mon Jan 17, 2011 9:08 pm Post subject: |
|
|
this might do the trick:
Code: | if(ctype_digit($string)&&strlen($string)==14) |
|
|
Back to top |
|
rodneyrehm Administrator
Joined: 30 Mar 2007 Posts: 674 Location: Germany, border to Switzerland
|
Posted: Mon Jan 17, 2011 9:43 pm Post subject: |
|
|
After having some confusing test results due to an enabled xdebug, we've now found
Code: | ctype_digit($string) && strlen($string)==14 |
to be the fastest solution. |
|
Back to top |
|
mohrt Administrator
Joined: 16 Apr 2003 Posts: 7368 Location: Lincoln Nebraska, USA
|
Posted: Mon Jan 17, 2011 9:45 pm Post subject: |
|
|
globe wrote: | After having some confusing test results due to an enabled xdebug, we've now found
Code: | ctype_digit($string) && strlen($string)==14 |
to be the fastest solution. |
well fastest, and the only one as accurate as preg_*
committed to svn trunk. |
|
Back to top |
|
Loki Smarty Rookie
Joined: 13 Jan 2011 Posts: 30
|
Posted: Mon Jan 17, 2011 10:07 pm Post subject: |
|
|
Code: |
<?
function getmicrotime()
{
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
$time_start = getmicrotime();
for($i=0;$i<1000000;$i++)
{
$string=str_pad($i, 14, "0", STR_PAD_LEFT);
if (preg_match('/^\d{14}$/', $string)) null;
}
echo sprintf("%01.3f sec.", getmicrotime()-$time_start)."<br />";
$time_start = getmicrotime();
for($i=0;$i<1000000;$i++)
{
$string=str_pad($i, 14, "0", STR_PAD_LEFT);
if(ctype_digit($string)&&strlen($string)==14) null;
}
echo sprintf("%01.3f sec.", getmicrotime()-$time_start)."<br />"; |
results (on windows):
Code: | 10.093 sec.
12.234 sec. |
So preg_match is the fastest way to check value. Thanks for your attention! |
|
Back to top |
|
rodneyrehm Administrator
Joined: 30 Mar 2007 Posts: 674 Location: Germany, border to Switzerland
|
Posted: Mon Jan 17, 2011 10:21 pm Post subject: |
|
|
urrm. although we only tested on osx and linux we did find the ctype solution to be faster.
is it possible you have xdebug (and or similar PECLs) active? they slow down certain function calls for some reason. My development machine has xdebug enabled (for obvious reasons). Only after disabling it did I get the same results I saw on some production systems I ran the test on.
also give microtime() another look. microtime(true) already returns a float, so you don't need to calculate that yourself…
Edit:
Code: | C:\Documents and Settings\rrehm\Desktop>php test.php
done: 1.2822089195251
done: 1.8049728870392
done: 2.0510950088501
C:\Documents and Settings\rrehm\Desktop>php --version
PHP 5.3.2 (cli) (built: Mar 3 2010 19:40:13)
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
|
ctype is fastest, followed by the inaccurate intval, followed by preg on last place.
your test shows the same result on my box:
Code: | C:\Documents and Settings\rrehm\Desktop>php test.php
4.677 sec.
3.548 sec. |
|
|
Back to top |
|
Loki Smarty Rookie
Joined: 13 Jan 2011 Posts: 30
|
Posted: Tue Jan 18, 2011 6:51 am Post subject: |
|
|
globe wrote: | is it possible you have xdebug (and or similar PECLs) active? |
You right - after disabling xdebug ctype variant becomes up to 35% faster than preg_match. |
|
Back to top |
|
Lemon Juice Smarty Pro
Joined: 24 May 2006 Posts: 109
|
Posted: Wed Jan 19, 2011 9:44 am Post subject: |
|
|
globe wrote: | After having some confusing test results due to an enabled xdebug, we've now found
Code: | ctype_digit($string) && strlen($string)==14 |
to be the fastest solution. |
That's nice but it can be sped up even more - if we are talking about such micro-optimizations. Just reverse the order:
Code: | strlen($string)==14 && ctype_digit($string) |
This will 2x faster for a huge majority of cases because:
1. If the string is a timestamp number, then it's certainly less than 14 characters long so ctype_digit will not have to be executed at all - 2x faster.
2. If the string is a descriptive string for strtotime it would be very rare that it's 14 characters long. All date and datetime formats from mysql are not 14 characters long - 2x faster for probably >90% of cases.
3. If the string is mysql timestamp format of YYYYMMDDHHMMSS then the execution time will be the same. The same for empty string (first if) and DateTime object (first elseif). |
|
Back to top |
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|
|