php - 如果我们从代码中设置时区,为什么 date() 的工作速度会提高一倍?

标签 php datetime timezone micro-optimization

您是否注意到,如果您在任何 date() 之前在脚本中设置实际时区,date() 函数的运行速度比平常快 2 倍称呼?我对此非常好奇。

看看这段简单的代码:

<?php

  $start = microtime(true);
  for ($i = 0; $i < 100000; $i++) date('Y-m-d H:i:s');
  echo (microtime(true) - $start);

?>

它只是使用 for 循环调用 date() 函数 100,000 次。我得到的结果总是在 1.6 秒 左右(Windows,PHP 5.3.5)但是……

如果我再次设置相同的时区,在开始前添加一条荒谬的线:

date_default_timezone_set(date_default_timezone_get());

我得到的时间低于 800 毫秒; ~ 2 倍快(相同的服务器)。

我四处寻找对此行为的任何合理解释,但没有任何成功。从我的角度来看,这个额外的行是没用的,但 PHP 不同意我的观点。

我在两台 linux 服务器(不同的 PHP 版本)上尝试了这个测试,得到了不同的结果时间,但比例 ~6:1

注意:php.ini 中的 date.timezone 属性已正确设置(欧洲/巴黎)。

我在这里搜索相关问题,但没有找到类似的问题。我还检查了 date_default_time_zone() function @ php.net 的手册并发现我不仅注意到了这一点,但仍然无法理解为什么会发生这种情况?

有人吗?

最佳答案

PHP 5.4 更新:

date_default_timezone_get 的描述中所述,从 PHP 5.4.0 开始,算法从系统信息中猜测时区 has been removed from the code (与 PHP 5.3 源代码对比)所以这种行为不再存在。

在我的开发服务器上运行计时测试以查看它的实际效果,我得到:

  • PHP 5.3.11:~720 毫秒
  • PHP 5.4.3:~470 毫秒

原答案:

我刚刚研究了 PHP 源代码。具体来说,所有相关代码都在/ext/date/php_date.c .

我开始假设如果您不为 date 提供时区,则调用 date_default_timezone_get 来获取时区。 Here's that function :

PHP_FUNCTION(date_default_timezone_get)
{
    timelib_tzinfo *default_tz;

    default_tz = get_timezone_info(TSRMLS_C);
    RETVAL_STRING(default_tz->name, 1);
}

好的,那么 get_timezone_info 是什么样的? This :

PHPAPI timelib_tzinfo *get_timezone_info(TSRMLS_D)
{
    char *tz;
    timelib_tzinfo *tzi;

    tz = guess_timezone(DATE_TIMEZONEDB TSRMLS_CC);
    tzi = php_date_parse_tzfile(tz, DATE_TIMEZONEDB TSRMLS_CC);
    if (! tzi) {
        php_error_docref(NULL TSRMLS_CC, E_ERROR, "Timezone database is corrupt - this should *never* happen!");
    }
    return tzi;
}

guess_timezone 呢? Here它是:

static char* guess_timezone(const timelib_tzdb *tzdb TSRMLS_DC)
{
    char *env;

    /* Checking configure timezone */
    if (DATEG(timezone) && (strlen(DATEG(timezone)) > 0)) {
        return DATEG(timezone);
    }
    /* Check environment variable */
    env = getenv("TZ");
    if (env && *env && timelib_timezone_id_is_valid(env, tzdb)) {
        return env;
    }
    /* Check config setting for default timezone */
    /*  ..... code omitted ....... */
#if HAVE_TM_ZONE
    /* Try to guess timezone from system information */
    /*  ..... code omitted ....... */
#endif
#ifdef PHP_WIN32
    /*  ..... code omitted ....... */
#elif defined(NETWARE)
    /*  ..... code omitted ....... */
#endif
    /* Fallback to UTC */
    php_error_docref(NULL TSRMLS_CC, E_WARNING, DATE_TZ_ERRMSG "We had to select 'UTC' because your platform doesn't provide functionality for the guessing algorithm");
    return "UTC";
}

好的,那么它如何与 date_default_timezone_set 交互?让我们看看 that function :

PHP_FUNCTION(date_default_timezone_set)
{
    char *zone;
    int   zone_len;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &zone, &zone_len) == FAILURE) {
        RETURN_FALSE;
    }
    if (!timelib_timezone_id_is_valid(zone, DATE_TIMEZONEDB)) {
        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Timezone ID '%s' is invalid", zone);
        RETURN_FALSE;
    }
    if (DATEG(timezone)) {
        efree(DATEG(timezone));
        DATEG(timezone) = NULL;
    }
    DATEG(timezone) = estrndup(zone, zone_len);
    RETURN_TRUE;
}

长话短说:如果您调用一次 date_default_timezone_set,那么 guess_timezone 会采用从 timezone 变量读取的快速路径(第一个条件满足,立即返回)。否则需要一些时间来计算默认时区,它没有被缓存(我猜是为了简单起见),如果你在循环中这样做,延迟就会开始显示。

关于php - 如果我们从代码中设置时区,为什么 date() 的工作速度会提高一倍?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5556789/

相关文章:

python默认参数值使用日期时间

javascript - 有没有办法在 Javascript `Date` 对象中表示 2012 年 10 月 21 日?

python - 如何在 Python 中查找第二天同一小时的 Unix 时间戳,包括 DST?

javascript - 为什么我不能从 jQuery/AJAX 调用这个 PHP 文件?

c++ - 在 C++ 中使用 mktime 的纪元

php - 我想用 am 或 pm 以 30 分钟为间隔显示时间

java - 从时间戳构造java.util.Date对象时发生时区问题

php - 为什么这个 PDO 语句会默默地失败?

php - 在 wordpress 的特定标签中显示 mysql 查询

PHP登录表单错误