While building some calendaring tools for a student portal, we noticed that on the course schedule page the date_now function was accounting for roughly .8secs of the total execution time.

Looking at the XHProf output, date_now gets called rather often within the processing of date data.

For example, looking at the DateObject::arrayErrors function (http://api.drupalize.me/api/drupal/function/DateObject%3A%3AarrayErrors/7) date_now is called at the top of the method.

Then in the for loop, forceValid is called for each iteration. And if you look at DateObject::forceValid (http://api.drupalize.me/api/drupal/function/DateObject%3A%3AforceValid/7) it too calls date_now.

And looking at date_now, it generates a new call to the DateObject constructor for each function call.

Looking at how fast the DateObject::construct method is, we'd want to minimize those calls whenever possible. Therefore I'd suggest adding some static caching on the date_now function.

Something along these lines:

<?php
/**
* A date object for the current time.
*
* @param object $timezone
* (optional) Optionally force time to a specific timezone, defaults to user
* timezone, if set, otherwise site timezone. Defaults to NULL.
*
* @param boolean $reset [optional]
* Cache reset flag
*
* @return object
* The current time as a date object.
*/
function date_now($timezone = NULL, $reset = FALSE) {
$now = &drupal_static(__FUNCTION__);

if (!isset($now) || $reset) {
$now = new DateObject('now', $timezone);
}

return $now;
}

Since we're dealing with time in seconds and the amount of time DateObject::construct takes to even run, having a cache on the "now" time seems reasonable. Though I'm not entirely sure of implication of this kind of change would have. But allowing a reset to be placed would allow anyone looking for up to the second (or at least as fast as DateObject::construct can run) should suffice.

As far as performance gains, in my XHProf testing, the original function accounted for 860,792 microseconds of execution time. With the static cache in place, that number dropped to 39,660 microseconds. (I've attached the screenshots).

I'd be happy to supply a patch if this change is acceptable.

Thanks.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

minorOffense’s picture

Status: Active » Needs review
FileSize
883 bytes

Here's a patch anyways ;-)

ckng’s picture

Status: Needs review » Reviewed & tested by the community

This is working, however as stated in original issue could use more testing.

cafuego’s picture

Status: Reviewed & tested by the community » Fixed

This might cause a problem for people who do timing using date_now(), but to be honest they have bigger fish to fry if they're in that position.

Perhaps it might be worthwhile passing REQUEST_TIME as argument to the DateObject, as I would expect that during a request 'now' is the time the request began. Anyway, we can revisit that if need be.

Applied to 7.x-2.x.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

kristofferwiklund’s picture

This patch has introduced a bug if date now is called with different time zones and also code that handles the result should not change it.

See related issues
#2261377: date_example_date() changed value of date_now()
#2261395: date_now is not respecting changes to timezone.