Managing timezones in Laravel applications can be crucial when you have users from different regions. In this article, I’ll walk you through a step-by-step process to manage user-specific timezones in Laravel 11.
We’ll set up authentication with Laravel UI, add a timezone column to the users table, and dynamically display timestamps based on the user’s timezone. Along the way, I’ll show you how to create a profile page for updating timezones and a posts page that displays "created at" dates tailored to each user.
Let’s make your application timezone-friendly and user-centric!
In this step, we'll install laravel 11 application using the following command.
composer create-project laravel/laravel example-app
Then, we'll install laravel UI and also install laravel scaffold auth using the following command.
composer require laravel/ui
php artisan ui bootstrap --auth
npm install
npm run build
Next, we'll create a migration using the following command.
php artisan make:migration add_timezone_column_users_table
php artisan make:migration create_posts_table
Migration:
<?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
{
//
}
};
<?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');
}
};
Migrate the table into the database using the following command.
php artisan migrate
Now, create the Traits folder in the app and create the HandlesTimezones.php file.
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");
}
}
Next, we'll create a model using the following command.
php artisan make:model Post
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',
];
}
}
Then, we'll define the routes in the web.php file.
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");
Now, we'll create a controller and add the following code to that file.
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.");
}
}
In this step, we'll update the app.blade.php file, create posts, and profile blade file.
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('/') }}">
How to Manage User Timezone in Laravel 11
</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
Now, run the laravel 11 application using the following command.
php artisan serve
You might also like:
In this article, we will see how to remove/delete files from public folders. We will give you a demo of how to remo...
Sep-14-2020
In this article, we will see how to validate email using jquery. we will use regular expression(regex) for email va...
Nov-09-2022
In this tutorial, we'll explore an example of installing Yajra Datatable in Laravel 11. In every project, it's e...
Apr-10-2024
In this guide, we'll see how to send email using a queue in laravel 11. Here we'll see the concept of queue...
Apr-12-2024