Playing with time intervals in WordPress

Playing with time intervals in WordPress is fun. Here are some tests I ran to calculate the amount of time left in the day until midnight.

I’ve recently had to think about calculating time intervals in a little WordPress plugin of mine, and I thought I would share my findings. Maybe some of you will have some ideas on how to improve things even further :)

Problem: I want to store the results of an expensive query in a transient for the day.

My first implementation was to set the transient for 24 hours:

set_transient( $transient_key, $query, DAY_IN_SECONDS );

Easy enough! DAY_IN_SECONDS is a default constant provided by WordPress to make those things easier.

That’s not exactly what I want, though. I don’t want data to be cached for 24 hours; I want it to be cached for the rest of the day, i.e. for the amount of time (seconds) left in the day until midnight.

If the query is first run on the site a minute before midnight, I don’t want to cache it for 24 hours; I want that data to be refreshed after midnight, since it’s already going to be the next day.

In my second implementation, I used WordPress’ current_time (reference) and strtotime like so:

$time_now          = (int) current_time( 'timestamp' );
$time_tonight      = (int) strtotime( 'today 24:00' );
$seconds_remaining = $time_tonight - $time_now;

Comparing 2 Unix timestamps seemed simple enough. It works.

However, WPCS wasn’t happy. The use of current_time() with timestamp is discouraged in core, as explained in this GitHub issue.

That led me to a third solution, using the improvements to the Date/Time components that were brought to Core a couple of years ago.

$time_now          = current_datetime();
$time_tonight      = new DateTimeImmutable(
    'today 24:00',
    wp_timezone()
);
$seconds_remaining = $time_tonight->getTimestamp() - $time_now->getTimestamp();

Excellent! No more phpcs warnings, and it works well. Bonus, it’s a tiny bit faster :)

Since current_datetime() is also creating a DateTimeImmutable object, I figured it may be easier to read if I were to replace that wrapper:

$time_now          = new DateTimeImmutable(
    'now',
    wp_timezone()
);
$time_tonight      = new DateTimeImmutable(
    'today 24:00',
    wp_timezone()
);
$seconds_remaining = $time_tonight->getTimestamp() - $time_now->getTimestamp();

That seems a bit easier to understand at first glance. It’s also faster.

For fun, here is a last alternative, that’s again a bit faster:

$timezone          = new DateTimeZone( wp_timezone_string() );
$time_now          = new DateTimeImmutable(
    'now',
    $timezone
);
$time_tonight      = new DateTimeImmutable(
    'today 24:00',
    $timezone
);
$seconds_remaining = $time_tonight->getTimestamp() - $time_now->getTimestamp();

I think I’ll keep using wp_timezone(); it’s readable and quick enough. And in the future, I’ll definitely try to use WordPress’ date and time components a bit more!

Would you have done it differently? I’d be curious to have your take on this!