Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why date() works twice as fast if we set time zone from code?

Have you noticed that date() function works 2x faster than usual if you set actual timezone inside your script before any date() call? I'm very curious about this.

Look at this simple piece of code:

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

It just calls date() function using for loop 100,000 times. The result I’ve got is always around 1.6 seconds (Windows, PHP 5.3.5) but…

If I set same time zone again adding one absurd line before start:

date_default_timezone_set(date_default_timezone_get()); 

I get a time below 800ms; ~2x faster (same server).

I was looking around to find any reasonable explanation for this behavior but did not have any success. From my angle, this additional line is useless but PHP doesn’t agree with me.

I have tried this test on two linux servers (different PHP versions) and got different resulting times but in proportion ~6:1.

Note: date.timezone property in php.ini has been properly set (Europe/Paris).

I was searching for related questions here and did not find anything similar. I've also checked manual for date_default_time_zone() function @ php.net and found that I'm not only one who noticed this, but still can't understand why that happens?

Anyone?

like image 320
Wh1T3h4Ck5 Avatar asked Apr 05 '11 18:04

Wh1T3h4Ck5


People also ask

Does JavaScript date have timezone?

JavaScript's internal representation uses the “universal” UTC time but by the time the date/time is displayed, it has probably been localized per the timezone settings on the user's computer. And, indeed, that's the way JavaScript is set up to work.

How does Java handle time zone issues?

If you cannot change the OS or the JVM timezone, you can still convert a Java Date/Time or Timestamp to a specific time zone using the following two JDBC methods: PreparedStatement#setTimestamp(int parameterIndex, Timestamp x, Calendar cal) – to convert the timestamp that goes to the database.

Does date need timezone?

NEVER use timezones with your dates because there is only one timezone: UTC. Anything else is a presentation format.


Video Answer


2 Answers

Update for PHP 5.4:

As documented in the description of date_default_timezone_get, starting from PHP 5.4.0 the algorithm to guess the timezone from system information has been removed from the code (contrast with the PHP 5.3 source) so this behavior no longer exists.

Running the timing test on my dev server to see it in action, I got:

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

Original answer:

I 've just looked into PHP source. Specifically, all relevant code is in /ext/date/php_date.c.

I started with the assumption that if you don't provide a timezone for date, date_default_timezone_get is called to get one. 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); } 

OK, so what does get_timezone_info look like? 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; } 

What about guess_timezone? Here it is:

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

OK, so how does that interact with date_default_timezone_set? Let's look at 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; } 

Long story short: if you call date_default_timezone_set once, then guess_timezone takes the fast path of reading from the timezone variable (the very first conditional is satisfied, and it returns immediately). Otherwise it takes some time to work out the default timezone, which is not cached (I guess for simplicity), and if you do that in a loop the delay starts to show.

like image 132
Jon Avatar answered Oct 17 '22 17:10

Jon


I'd imagine it has to determine the timezone for itself each time it's called unless explicitly specified, which adds to the function runtime.

But really, does it matter? How many scripts are you likely to make that call date() 100,000 times per run?

like image 23
GordonM Avatar answered Oct 17 '22 17:10

GordonM