Dealing with outputting dates in Laravel -- Let Blade components handle it cover image

Dealing with outputting dates in Laravel -- Let Blade components handle it

May 11, 2020

programming

If you’re working on a Laravel app that may:

  • Have users logging in across the world
  • Be installed by developers in different timezones
  • Have some application dates output in a single format

Leave your applications timezone on UTC and let a Laravel Blade component do the rest. I’ll show you what I mean.

For this, we’ll be using Laravel 7’s new Blade components feature.

Creating the Blade Component

First, let's whip up a new component. We'll call it DateTime:

We'll generate an inline component using the --inline flag. We don't need a separate view for this bad boy.

php artisan make:component DateTime --inline

This component name allows us to render it in a really easy and memorable way in our Blade:

<x-datetime/>

Now we need to be able to pass a Carbon date into it. We'll use a parameter simply named date.

This is what we're going for:

<x-datetime date="$post->created_at"/>

Looks nice, right? Let's get to the guts of the component.

The Blade Component

Laravel will generate a new class inside of your app/View/Component directory named DateTime.php.

We want this component to do a couple things:

  1. Set the timezone to the users preference
  2. Set a common date format that all dates will be output to

Copy and paste the below completed component, overwriting the generated code:

<?php

namespace App\View\Components;

use Carbon\Carbon;
use Illuminate\View\Component;

class DateTime extends Component
{
    /**
     * The date.
     *
     * @var Carbon
     */
    public $date;

    /**
     * The date format.
     *
     * @var string|null
     */
    public $format;

    /**
     * Create a new component instance.
     *
     * @param Carbon      $date
     * @param string|null $format
     *
     * @return void
     */
    public function __construct(Carbon $date, $format = null)
    {
        $this->date = $date->setTimezone($this->timezone());
        $this->format = $format;
    }

    /**
     * Format and render the date.
     *
     * @return string
     */
    public function render()
    {
        return $this->date->format($this->format());
    }

    /**
     * Get the format for the date.
     *
     * @return string
     */
    protected function format()
    {
        return $this->format ?? 'Y-m-d H:i:s';
    }

    /**
     * Get the timezone to convert the date to.
     *
     * @return string
     */
    protected function timezone()
    {
        return optional(auth()->user())->timezone ?? 'America/Toronto';
    }
}

Notice in the timezone() method, if there is an authenticated user, we will use their timezone they have saved on their user account. Otherwise, we will use a default timezone to display dates in. This would likely be a timezone you expect most of your user-base to be from.

The above implementation assumes you have created a timezone column on your users table that will be available for users to set. This gives a lot of flexibility. For example, if someone who travels often is using your app, they could simply change their timezone and see all outputted application dates in their time, rather than the servers time.

Now we can stop writing this to output dates in all of our views:

{{ $post->created_at->format("Y-m-d H:i:s") }}

And write this instead:

<x-datetime date="$post->created_at"/>

We can also set the format parameter if we needed to override the default format:

<x-datetime date="$post->created_at" format="Y-m-d"/>

Blade components have such great possibilities for cleaning up these types of operations in our view files. I'm seeing more and more opportunities as I continue to work with Laravel 7.

Hope you enjoyed this one!