¿Por qué date () funciona el doble de rápido si establecemos la zona horaria desde el código?


¿Ha notado que la función date() funciona 2 veces más rápido de lo habitual si establece la zona horaria real dentro de su script antes de cualquier llamada date()? Tengo mucha curiosidad sobre esto.

Mira este simple fragmento de código:

<?php

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

?>

Simplemente llama a la función date() usando el bucle for 100,000 veces. El resultado que tengo es siempre alrededor de 1.6 segundos (Windows, PHP 5.3.5) pero {

Si vuelvo a establecer la misma zona horaria añadiendo una línea absurda antes de empezar:

date_default_timezone_set(date_default_timezone_get());

Consigo un tiempo por debajo de 800ms; ~2 veces más rápido (mismo servidor).

Estaba mirando a mi alrededor para encontrar una explicación razonable para este comportamiento, pero no tuve ningún éxito. Desde mi ángulo, esta línea adicional es inútil, pero PHP no está de acuerdo conmigo.

He probado esta prueba en dos servidores linux (diferentes versiones de PHP) y obtuve diferentes tiempos resultantes, pero en proporción ~6:1.

Nota: fecha.propiedad timezone en php.ini se ha configurado correctamente (Europa / París).

Estaba buscando preguntas relacionadas aquí y no encontré nada similar. También he comprobado el manual para date_default_time_zone() function @ php.net y descubrí que no solo soy uno que se dio cuenta de esto, sino que todavía no puedo entender por qué sucede eso?

¿Alguien?

Author: ROMANIA_engineer, 2011-04-05

2 answers

Actualización para PHP 5.4:

Como se documenta en la descripción de date_default_timezone_get, a partir de PHP 5.4.0 el algoritmo para adivinar la zona horaria a partir de la información del sistema ha sido eliminado del código (en contraste con la fuente PHP 5.3) por lo que este comportamiento ya no existe.

Ejecutando la prueba de sincronización en mi servidor dev para verlo en acción, obtuve:

  • PHP 5.3.11: ~720ms
  • PHP 5.4.3: ~470ms

Respuesta original:

I 've acabo de mirar el código fuente de PHP. Específicamente, todo el código relevante está en /ext/date/php_date.c.

Comencé con la suposición de que si no proporcionas una zona horaria para date, date_default_timezone_get se llama para conseguir uno. Aquí está esa función :

PHP_FUNCTION(date_default_timezone_get)
{
    timelib_tzinfo *default_tz;

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

Bien, entonces, ¿cómo se ve get_timezone_info? Esto :

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;
}

¿Qué pasa con guess_timezone? Aquí es:

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";
}

Bien, entonces, ¿cómo interactúa eso con date_default_timezone_set? veamos que función :

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;
}

En resumen: si llamas a date_default_timezone_set una vez, entonces guess_timezone toma el camino rápido de leer desde la variable timezone (el primer condicional se cumple y regresa inmediatamente). De lo contrario, toma algún tiempo calcular la zona horaria predeterminada, que no se almacena en caché (supongo que por simplicidad), y si lo hace en un bucle, el retraso comienza a mostrarse.

 41
Author: Jon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-17 12:45:39

Me imagino que tiene que determinar la zona horaria por sí mismo cada vez que se llama a menos que se especifique explícitamente, lo que se suma al tiempo de ejecución de la función.

Pero, realmente, ¿importa? ¿Cuántos scripts es probable que hagas esa llamada date() 100,000 veces por ejecución?

 2
Author: GordonM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-05 18:50:05