Human readable Intervals
Tags: php, laravel, tipstricks
Published: 2020-12-13 18:25:59

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](https://twitter.com/marcelpociot) posted this [solution on Twitter](https://twitter.com/marcelpociot/status/1176018954986426368).

If you don't know the class already - the [nesbot/carbon](https://github.com/briannesbitt/Carbon) (required by Laravel itself) provides the `\Carbon\CarbonInterval` class ([docs](https://carbon.nesbot.com/docs/#api-interval)).

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](https://twitter.com/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
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
# production
PASSWORD_RESET_DECAY="7 days"
# staging
PASSWORD_RESET_DECAY="1 day"
# development
PASSWORD_RESET_DECAY="6 hours"
# local
PASSWORD_RESET_DECAY="10 minutes"
```