Time left strings with Carbon and Laravel string helper

Tag: Laravel 5.0+

This is taken from a post and discussion on Laravel Quick Tips that people found to be pretty useful, and so I thought I'd expand on it a little and share.

I'm sure you've all had to do a human-readable "time left" before - for example, an auction countdown where there were "5 hours left!". Not hard, just messy.

Unless you're using Laravel and Carbon. It's dead easy.

This can be written in a variety of ways according to your needs. To make it simple to follow along if you want to try it out yourself, I'm just going to use a mutator, but of course the important code can be shifted to a class and made more generic. A downside of doing this in a mutator is that it is tightly coupled to our model and can't be as easily tested or shared across the application (or reused in other applications without the old "copy/paste" migration technique).

We're going to use the example of a product on auction. We need to make a field on our Eloquent model, `expires_at` and - this is important - add it to the $dates array on our model.

If you aren't aware, any field added to that array will be cast as a Carbon date. A Carbon date is a class that extends the DateTime object using the Carbon Library. This was added to Laravel itself some versions ago, and is used in the Eloquent Model source to cast `created_at` and `updated_at` automatically. You can add any date field of your own and leverage the power of Carbon by simply using:

protected $dates = ['expires_at'];

Next, I'm adding a function to the model called displayHumanTimeLeft(). I like to think of functions as actions and name them so, so this says exactly what it does. I'll grab a Carbon instance for right now:

public function displayHumanTimeLeft() { $now = Carbon::now(); }

Carbon uses `_toString()` to allow you to simply echo your dates, which is why you may not have noticed this before, but it is actually a more complex object.

From here my version may branch off a bit from what you actually need to display, but I'm just going to show you how to set up "X day(s) left". We only want to show this if there is at least one day left, otherwise it will drop down to similar code calculating hours, etc.

public function displayHumanTimeLeft() { $now = Carbon::now(); if ($now->diffInDays($this->expires_at) > 0) { return $now->diffInDays($this->expires_at) . str_plural(' day', $now->diffInDays($this->expires_at)). ' left'; } }

Let's look at that and see what it's doing. First, diffInDays() compares two Carbon dates and gives you an integer. So if it is > 0, it will run that code. The second part is why Laravel can be so wonderful at times. We want to use the string " days left". But of course, if it is only 1 day, we want the singular.

If you look in the Illuminate/Support/helpers file, you'll see that `str_plural()` actually takes a second argument. It defaults to '2', meaning the default will always be the plural form, but if you pass it '1' then the Str::plural will pass it to the 'Pluralizer', which will figure out for you if it should pluralize or not.

So the only thing we have to do is pass to the Carbon::now() our Carbon date we are comparing (`expires_at`), tell it if we want to compare days, hours, etc, and finally feed that to the Laravel helper function. My example is a simpler form - if it is less than a day, it would drop down to find hours instead, then minutes and seconds. You can make the full "4 days, 2 hours, 5 minutes" type string with a little more manipulation.

That's it - you're finished! Have a look at the Carbon docs to see the other related functions you may want for finding the difference in other time periods.

Hope that helps!