Ответ 1
Обновление для PHP 5.4:
Как описано в описании date_default_timezone_get
, начиная с PHP 5.4.0 алгоритм, чтобы угадать часовой пояс из системной информации был удален из кода (в отличие от источника PHP 5.3), поэтому этого поведения больше не существует.
Запуск теста времени на моем dev-сервере, чтобы увидеть его в действии, я получил:
- PHP 5.3.11: ~ 720 мс
- PHP 5.4.3: ~ 470ms
Оригинальный ответ:
Я только что изучил источник PHP. В частности, весь соответствующий код находится в /ext/date/php_date.c
.
Я начал с предположения, что если вы не предоставляете часовой пояс для date
, вызывается date_default_timezone_get
для его получения. Здесь эта функция:
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
? Это:
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
? Здесь это:
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
?. Посмотрите эту функцию:
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
(выполняется первое условие, и оно немедленно возвращается). В противном случае требуется некоторое время для разработки часового пояса по умолчанию, который не кэшируется (я думаю, для простоты), и если вы сделаете это в цикле, задержка начнет отображаться.