Quick Tip: Display Dates Relatively in Laravel

John Kariuki

We have previously looked at the Carbon package by Brian Nesbitt as well as all the functionality it adds to PHP's DateTime class.

In this article, we will take a look at how Laravel takes advantage of this package.

Introduction

As already mentioned, The carbon class does not rebuild PHP's DateTime class from scratch, it builds upon it.

<?php
namespace Carbon;

class Carbon extends \DateTime
{
    // code here
}

This means that you can access the default functionality of PHP's DateTime class on top of the awesomeness that is Carbon.

Laravel already includes the Carbon class by default so we do not need to install it separately. To get started with Carbon in Laravel, simply create a new project using the laravel command.

$ laravel new scotch-dates

Carbon Dating in Laravel

See what I did there? Turns out Brian Nesbitt had the same idea in mind while creating the Carbon package.

Now by default, if the timestamps variable in a Laravel model class is not explicitly set to false, then it is expected that it's corresponding table should have the created_at and updated_at columns.

We can however go ahead and add our own date columns such as activated_at, dob or any other depending on the type of application or the nature of the Laravel model we are working on.

But how does laravel know that these fields should be cast to date?

Simple. Add all the date fields to the protected dates variable in the model class.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * The attributes that should be mutated to dates.
     *
     * @var array
     */
    protected $dates = [
        'created_at',
        'updated_at',
        'activated_at',
        'dob'
    ];
}

Setup

In our scotch-dates application that we just created, we already have a our first migration setup for the user's table. We will need to have some user records to work with, so let's seed some data in our database with the factory helper method on tinker.

$ php artisan tinker
>>> factory('App\User', 10)->create()

To get started, we'll go ahead and create a new UserController class to get all the user's from the user's table into a view and add a /users route.

/routes/web.php

Route::get('/', function () {
    return view('welcome');
});

Route::get('/users', 'UserController@users');

I have gone ahead to add a few helper variables courtesy of the Carbon class to give me access to a few dates such as now, yesterday, today and tomorrow.

/app/Http/Controllers/UserController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\User;
use Carbon\Carbon;

class UserController extends Controller
{
    public function users()
    {
        return view('users', [
            'users' => User::all(),
            'now' => Carbon::now(),
            'yesterday' => Carbon::yesterday(),
            'today' => Carbon::today(),
            'tomorrow' => Carbon::tomorrow()
        ]);
    }
}

Let's play around with Carbon dates on the user's view.

Displaying Absolute Dates

Having setup our user's details and passed them on to the users view, we can now display each of the users with the following blade template.

<table>
    <tr>
        <th>Name</th>
        <th>Created</th>
    </tr>

    @foreach($users as $user)
        <tr>
            <td>{{ $user->name }}</td>
            <td>{{ $user->created_at }}</td>
        </tr>
    @endforeach
</table>

With this, we should have the following.

Absolute dates

Displaying Dates Relatively

Displaying dates relatively is quite popular since it is easier for humans to read out a post as created 30 minutes ago as opposed to 2017-01-08 19:15:20.

Let's play around with the Carbon class to see how we can display the dates relatively in different ways.

When comparing a value in the past to default now:

This comes in handy when you want to display a date in the past with reference to the current time. This would be something like:

  • A few seconds ago
  • 30 minutes ago
  • 2 days ago
  • 1 year ago

To achieve this, we simply use the diffForHumans method.

$user->created_at->diffForHumans()
// 1 hour ago

When comparing a value in the future to default now:

You'd probably want to use this in cases where you need to publish a post in the future or show an expiration date.

  • 1 hour from now
  • 5 months from now
$user->created_at->addDays(5)->diffForHumans() 
//5 days from now

When comparing a value in the past to another value:

  • 1 hour before
  • 5 months before
$yesterday->diffForHumans($today)
//1 day before

When comparing a value in the future to another value:

  • 1 hour after
  • 5 months after
$tomorrow->diffForHumans($today)
//1 day after

More About Diffs

While it may be nice to display to the user fully quallified diffs such as 2 hours ago, you may at times simply want to show the user the value without the text.

This may come in handy where you have many comments coming in and the text is just too repetitive. diffInSeconds() in particular can be used in cases where the difference in time between two entities, say, lap times, is of significance.

This can achieved by the diffInYears, diffInMonths(), diffInWeeks(), diffInDays(), diffInWeekdays(), diffInWeekendDays() diffInHours(), diffInMinutes() and diffInSeconds() methods.

$user->created_at->diffInHours(); //2
$user->created_at->diffInMinutes(); //134
$user->created_at->diffInSeconds(); //8082

The carbon class also come with methods that return the number of seconds since midnight or to the end of the day (midnight) which can be used to create a countdown, say, for a product sale.

$now->secondsSinceMidnight() //77825
$now->secondsUntilEndOfDay() //8574

Conclusion

There's alot you can achieve with the Carbon class and sometimes you will not find out about a functionality that it provides until you need it.

Take a look at the documentation here. Happy Carbon dating!

John Kariuki

18 posts

Software developer at Andela. Proficient in PHP with Laravel and Codeigniter.

Conversant with MEAN(MongoDB, Express.js, AngularJS, Node.js) and currently learning Python and Go.

Avid blog reader and fascinated by drones.

I play basketball, swim and jog in my free time.