Demo-Project: Managing Timezones for Every User in Laravel

To demonstrate how Laravel works with timezones, we’ve created a small demo-project. User registration is expanded with Timezone field, and then every user sees the data in their own timezone.

The subject is really simple – event management system with one field: events.start_time, which would be stored in UTC timezone in the database, and then converted to/from timezone when needed.

The project was partly built with our QuickAdminPanel generator, so I won’t explain all the code, only the parts that are needed for timezone topic. The whole code is available on Github for reference.

Step 1. Registration form

In the database, we need a timezone column, as a string with default value Europe/London:

Schema::create('users', function (Blueprint $table) {

In app/User.php model we add that as a fillable:

class User extends Authenticatable
    use Notifiable;
    protected $fillable = ['name', 'email', 'password', 'remember_token', 'timezone'];
    // ... other model code

In registration view we add it as a dropdown field:

To do that, we use camroncade/timezone package. In app/Http/Controllers/Auth/RegisterController.php we override showRegistrationForm() method, that is originally located in RegistersUsers trait:

 * Show the application registration form.
 * @return \Illuminate\Http\Response
public function showRegistrationForm()
    $timezone_select = Timezone::selectForm(
        ['class' => 'form-control', 'name' => 'timezone']
    return view('auth.register', compact('timezone_select'));

And then in resources/views/auth/register.blade.php we just use the variable to show the dropdown:

{!! $timezone_select !!}

Finally, in the same app/Http/Controllers/Auth/RegisterController.php we override create() method to save the timezone field:

 * Create a new user instance after a valid registration.
 * @param  array $data
 * @return User
protected function create(array $data)
    $user = User::create([
        'name'     => $data['name'],
        'email'    => $data['email'],
        'password' => bcrypt($data['password']),
        'timezone' => $data['timezone'],

    return $user;

Step 2. Saving the Event in User’s Timezone

In the event adding form, there is a simple datetime picker, without any timezone. So we assume that user enters the time in their own timezone.

When saving the time, we use Laravel Eloquent mutator function, in app/Event.php:

use Camroncade\Timezone\Facades\Timezone;
// ...

 * Set attribute to date format
 * @param $input
public function setStartTimeAttribute($input)
    $this->attributes['start_time'] =
        Timezone::convertToUTC($input, auth()->user()->timezone,  'Y-m-d H:i:s');

Step 3. Viewing Event in User’s Timezone

Final step – viewing the event list in user’s timezone. So what if event is entered by one user in London, and want to be viewed by another user in San Francisco?

We use Laravel Eloquent accessor function, again in app/Event.php we add this method:

 * Get attribute from date format
 * @param $input
 * @return string
public function getStartTimeAttribute($input)
    return Timezone::convertFromUTC($input, auth()->user()->timezone, 'Y-m-d H:i:s');

And that’s it, all you need to do now is create a list, so in app/Http/Controllers/Admin/EventsController.php we have this:

public function index()
    $events = Event::all();
    return view('', compact('events'));

And in resources/views/events/index.blade.php, we have a simple Blade table:

<table class="table table-bordered table-striped">
            <th> </th>


        @if (count($events) > 0)
            @foreach ($events as $event)
                <tr data-entry-id="{{ $event->id }}">
                    <td field-key='title'>{{ $event->title }}</td>
                        <td field-key='start_time'>{{ $event->start_time }}</td>
                                <a href="{{ route('',[$event->id]) }}" class="btn btn-xs btn-primary">@lang('global.app_view')</a>
                                <a href="{{ route('',[$event->id]) }}" class="btn btn-xs btn-info">@lang('global.app_edit')</a>
                                {!! Form::open(array(
                                    'style' => 'display: inline-block;',
                                    'method' => 'DELETE',
                                    'onsubmit' => "return confirm('".trans("global.app_are_you_sure")."');",
                                    'route' => ['', $event->id])) !!}
                                {!! Form::submit(trans('global.app_delete'), array('class' => 'btn btn-xs btn-danger')) !!}
                                {!! Form::close() !!}

                <td colspan="7">@lang('global.app_no_entries_in_table')</td>

As a result, you see the list of events, like this:

Repository on Github:

Like our articles?
Check out our Laravel online courses!


  1. i create more than different project in laravel. now i want maintain all project to one super admin. this is possible. if yes, how to make it?

  2. Hm… Almost perfect for my taste! Thinking if there is a way to avoid writing an accessor for each model to do this. I would be cool if you could spot datetime columns and automatically apply this logic, so you don’t need to think about this ever again even in future models.

  3. But Laravel doesn’t save *_at fields in UTC timezone. It saves them in php’s current timezone, which is not mysql’s connection’s timezone, because Laravel doesn’t set that. I’ve always found this odd. Laravel timezones only work if you never ever change it. That’s why I never save *_at fields as mysql ‘timestamp’ fields, but as ‘int’ with a real UTC stamp. Always works from everywhere to everywhere.


Please enter your comment!
Please enter your name here