How to Manage User Timezone in Laravel?
In this post, I will show you how to manage dynamic user timezone in laravel application.
In this example, we will set up authentication using Laravel UI and add a "timezone" column to the users table so each user can have their own timezone. We will also create a posts table with columns for "title" and "body." A profile page will be added where users can update their timezone, and a posts page will show a list of posts and allow users to create new ones. The "created at" date and time for posts will be displayed according to the user's timezone. To manage timezones dynamically, we will create a trait. Let's get started!.
Step 1: Install Laravel 11
This step is not required; however, if you have not created the Laravel app, then you may go ahead and execute the below command:
composer create-project laravel/laravel example-app
Step 2: Create Auth using Scaffold
Now, in this step, we will create an auth scaffold command to generate login, register, and dashboard functionalities. So, run the following commands:
Laravel 11 UI Package:
composer require laravel/ui
Generate Auth:
php artisan ui bootstrap --auth
npm install
npm run build
Step 3: Create Migrations
Here, we will create posts and add timezone column to users table. so, let's run the following command:
php artisan make:migration add_timezone_column_users_table
php artisan make:migration create_posts_table
now, let's update the following migrations:
database/migrations/2024_06_18_140624_add_timezone_column_users_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->string('timezone')->nullable();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
//
}
};
database/migrations/2024_06_18_140906_create_posts_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('body');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('posts');
}
};
now, Let's run the migration command:
php artisan migrate
Step 4: Create HandlesTimezones Trait
Here, you need to create "Traits" folder in app and create HandlesTimezones.php file. so, let's do it:
app/Traits/HandlesTimezones.php
<?php
namespace App\Traits;
use Auth;
use Carbon\Carbon;
trait HandlesTimezones{
/**
* Write code on Method
*
* @return response()
*/
public function getCreatedAtAttribute($value)
{
return $this->convertTimeZoneToUserTimezone($value);
}
/**
* Write code on Method
*
* @return response()
*/
public function getUpdatedAtAttribute($value)
{
return $this->convertTimeZoneToUserTimezone($value);
}
/**
* Write code on Method
*
* @return response()
*/
protected function convertTimeZoneToUserTimezone($value){
$timezone = Auth::check() & Auth::user()->timezone ? Auth::user()->timezone : config("app.timezone");
return Carbon::parse($value)->timezone($timezone)->format("Y-m-d H:i:s");
}
}
Step 5: Create and Update Models
Here, we will create Post model using the following command. we also need to update User model here. we will write relationship and some model function for like and dislike.
php artisan make:model Post
now, update the model file with hasMany() relationship:
app/Models/Post.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Traits\HandlesTimezones;
class Post extends Model
{
use HandlesTimezones;
protected $fillable = ["title", "body"];
}
app/Models/User.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name',
'email',
'password',
'timezone'
];
/**
* The attributes that should be hidden for serialization.
*
* @var array
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* Get the attributes that should be cast.
*
* @return array
*/
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
}
Step 6: Create Routes
In this step, we need to create some routes for profile and posts. So open your "routes/web.php" file and add the following route.
routes/web.php
<?php
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('welcome');
});
Auth::routes();
Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home');
Route::get('/posts', [App\Http\Controllers\PostController::class, 'index']);
Route::post('/posts', [App\Http\Controllers\PostController::class, 'store'])->name("posts.store");
Route::get('/profile', [App\Http\Controllers\ProfileController::class, 'profile']);
Route::post('/profile', [App\Http\Controllers\ProfileController::class, 'profileUpdate'])->name("profile.update");
Step 7: Create Controller
Here, we will create new PostController and ProfileController with methods. So let's put the code below.
app/Http/Controllers/PostController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Post;
class PostController extends Controller
{
/**
* Write code on Method
*
* @return response()
*/
public function index(Request $request)
{
$posts = Post::latest()->get();
return view("posts", compact('posts'));
}
/**
* Write code on Method
*
* @return response()
*/
public function store(Request $request)
{
Post::create([
"title" => $request->title,
"body" => $request->body,
]);
return back()->with('success', "post created.");
}
}
app/Http/Controllers/ProfileController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class ProfileController extends Controller
{
/**
* Write code on Method
*
* @return response()
*/
public function profile(Request $request)
{
$timezones = [
'Asia/Kolkata' => 'Asia/Kolkata',
'America/New_York' => 'America/New_York',
'Europe/London' => 'Europe/London',
'Asia/Tokyo' => 'Asia/Tokyo',
'Australia/Sydney' => 'Australia/Sydney',
];
return view("profile", compact('timezones'));
}
/**
* Write code on Method
*
* @return response()
*/
public function profileUpdate(Request $request)
{
$user = auth()->user();
$user->name = $request->name;
$user->email = $request->email;
$user->timezone = $request->timezone;
$user->save();
return back()->with('success', "profile updated.");
}
}
Step 8: Create and Update Blade Files
In this step, we will update app.blade.php file and create posts, profile blade file. so, let's update it.
resources/views/layouts/app.blade.php
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ config('app.name', 'Laravel') }}</title>
<!-- Fonts -->
<link rel="dns-prefetch" href="//fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=Nunito" rel="stylesheet">
<!-- Scripts -->
@vite(['resources/sass/app.scss', 'resources/js/app.js'])
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />
@yield('script')
</head>
<body>
<div id="app">
<nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="{{ url('/') }}">
Laravel Send Realtime Notification using Reverb
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<!-- Left Side Of Navbar -->
<ul class="navbar-nav me-auto">
</ul>
<!-- Right Side Of Navbar -->
<ul class="navbar-nav ms-auto">
<!-- Authentication Links -->
@guest
@if (Route::has('login'))
<li class="nav-item">
<a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a>
</li>
@endif
@if (Route::has('register'))
<li class="nav-item">
<a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a>
</li>
@endif
@else
<li class="nav-item">
<a class="nav-link" href="/posts">Posts</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/profile">Profile</a>
</li>
<li class="nav-item dropdown">
<a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
{{ Auth::user()->name }}
</a>
<div class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="{{ route('logout') }}"
onclick="event.preventDefault();
document.getElementById('logout-form').submit();">
{{ __('Logout') }}
</a>
<form id="logout-form" action="{{ route('logout') }}" method="POST" class="d-none">
@csrf
</form>
</div>
</li>
@endguest
</ul>
</div>
</div>
</nav>
<main class="py-4">
@yield('content')
</main>
</div>
</body>
</html>
resources/views/posts.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-12">
<div class="card">
<div class="card-header">{{ __('Posts') }}</div>
<div class="card-body">
<form method="POST" action="{{ route('posts.store') }}">
@csrf
@session('success')
<div class="alert alert-success">
{{ $value }}
</div>
@endsession
<div class="mt-2">
<label>Title:</label>
<input type="text" name="title" class="form-control">
@error('title')
<span class="text-danger">{{ $message }}</span>
@enderror
</div>
<div class="mt-2">
<label>Body:</label>
<textarea class="form-control" name="body"></textarea>
@error('body')
<span class="text-danger">{{ $message }}</span>
@enderror
</div>
<div class="mt-2">
<button class="btn btn-success">Submit</button>
</div>
</form>
<table class="table table-striped table-bordered mt-3">
<thead>
<tr>
<th>ID</th>
<th>Title</th>
<th>Body</th>
<th>Creation Date</th>
</tr>
</thead>
<tbody>
@foreach($posts as $post)
<tr>
<td>{{ $post->id }}</td>
<td>{{ $post->title }}</td>
<td>{{ $post->body }}</td>
<td>{{ $post->created_at }}</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
@endsection
resources/views/profile.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-12">
<div class="card">
<div class="card-header">{{ __('Profile') }}</div>
<div class="card-body">
<form method="POST" action="{{ route('profile.update') }}">
@csrf
@session('success')
<div class="alert alert-success">
{{ $value }}
</div>
@endsession
<div class="mt-2">
<label>Name:</label>
<input type="text" name="name" class="form-control" value="{{ auth()->user()->name }}">
@error('name')
<span class="text-danger">{{ $message }}</span>
@enderror
</div>
<div class="mt-2">
<label>Email:</label>
<input type="email" name="email" class="form-control" value="{{ auth()->user()->email }}">
@error('email')
<span class="text-danger">{{ $message }}</span>
@enderror
</div>
<div class="mt-2">
<label>Timezone:</label>
<select class="form-control" name="timezone">
@foreach($timezones as $key => $label)
<option value="{{ $key }}" {{ auth()->user()->timezone == $key ? 'selected' : '' }}>
{{ $label }}
</option>
@endforeach
</select>
@error('email')
<span class="text-danger">{{ $message }}</span>
@enderror
</div>
<div class="mt-2">
<button class="btn btn-success">Submit</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
Run Laravel App:
All the required steps have been done, now you have to type the given below command and hit enter to run the Laravel app:
php artisan serve
Now, Go to your web browser, type the given URL and view the app output:
http://localhost:8000/
Now, you can register new user and go to profile page.
select timezone and see the timezone from posts list page.
[VIDEO]
I hope it can help you...
Hardik Savani
I'm a full-stack developer, entrepreneur and owner of ItSolutionstuff.com. I live in India and I love to write tutorials and tips that can help to other artisan. I am a big fan of PHP, Laravel, Angular, Vue, Node, Javascript, JQuery, Codeigniter and Bootstrap from the early stage. I believe in Hardworking and Consistency.
We are Recommending you
- Laravel Breeze Login with Google Auth Example
- Laravel Datatables Relationship with Filter Column Example
- Laravel Datatables Date Format with created_at Example
- Laravel Eloquent Find with Trashed Record Example
- How to Read JSON File in Laravel?
- Customize Laravel Jetstream Registration and Login Example
- Laravel Breeze Auth: Login With Email Or Username Example
- Laravel UI Auth: Login With Email Or Username Example
- How to Implement Email Verification in Laravel?
- How to Customize Laravel Breeze Authentication?
- Laravel Breeze Change Redirect After Login/Register
- Laravel 11 Generate UUID Example
- Laravel 11 Event Broadcasting Tutorial