Human readable Intervals

Photo by Agรช Barros on Unsplash

Human readable Intervals

Every Laravel application has several configuration values that represent a given amount of seconds or minutes. Like the session.lifetime, auth.password_timeout, queue.connections.*.retry_after and a lot more. By default all these values are a single integer like 10800, some of them even missing the unit in the description.

Multiplication

I bet that most of you know and have already done the easiest way - replace the single integer with a multiplication like 3 * 60 * 60 which is the same as 10800. Another benefit is that you can guess what's the interval as it's days * minutes * seconds. But there are still problems:

  1. it requires brain capacity to parse the multiplication
  2. not all intervals are seconds - how would you differentiate between 10 * 60 (10 hours in minutes) and 10 * 60 (10 minutes in seconds)
  3. it gets even harder when you need an interval like "2 days 6 hours" in seconds (2 * 24 * 60 * 60) + (6 * 60 * 60)

Luckily there's a solution for both issues.

Carbon Interval

Some time ago @marcelpociot posted this solution on Twitter.

If you don't know the class already - the nesbot/carbon (required by Laravel itself) provides the \Carbon\CarbonInterval class (docs).

This class comes with a human-readable fluent API to write your interval however you want. The important part is the magic property totalSeconds - similar properties exist for minutes, days and so on.

php
use Carbon\CarbonInterval;

CarbonInterval::days(2)->hours(6)->totalSeconds;

This is helpful in every part of your application - not only the configuration but also the real app code, for example cache TTL, signed URL expiration and wherever you need a given amount of seconds, minutes or other time units.

Constants

@devfrey asked how this works with constants.
Short: it doesn't.
I would recommend using the multiplication or single integer solution with an explanatory comment. I'm always using two comments - one above the const which describes the value and one at the end of the line that contains the unit.

php
// 5 minutes
const DEFAULT_TTL = 5 * 60; // seconds

// 7 days
const REMINDER_DELAY = 7 * 24 * 60; // minutes

Environment Variables

In some cases you possibly want to use a .env variable to define your config interval and it should be possible to change the insert units - for example for development/testing purposes. So by default it's 7 days but you want to be able to set it to 5 minutes without adjusting your code or complex conditions. The solution is the static \Carbon\CarbonInterval::fromString() method that accepts a string, similar but different to strtotime() function.

In one of our projects we had to prevent password reset for 7 days after it was successfully reset. But for sure we had to use something like 5-10 minutes on our local machines and several hours on our staging system.

php
config/auth.php
use Carbon\CarbonInterval;

return [
    // ...

    'password_reset_decay' => CarbonInterval::fromString(env('PASSWORD_RESET_DECAY', '7 days'))->totalSeconds,

    // ...
];

And in your .env file you can define the values like the following.

ini
.env
# production
PASSWORD_RESET_DECAY="7 days"
# staging
PASSWORD_RESET_DECAY="1 day"
# development
PASSWORD_RESET_DECAY="6 hours"
# local
PASSWORD_RESET_DECAY="10 minutes"