laravel-user-timezone maintained by anjan-talukdar
Laravel User Timezone
A lightweight, zero-boilerplate Laravel package that automatically displays timestamps and custom datetime columns in the user's local timezone—without cluttering your Blade views, API resources, or controllers.
🚀 Key Features
- Automatic Timezone Resolution Hierarchy:
- Authenticated User model setting (
$user->timezone) - Browser cookie (
user_timezone) auto-set via lightweight JS snippet - Session value (
session('user_timezone')) - Configured default fallback (
Asia/Kolkataor your custom default)
- Authenticated User model setting (
- Single Unified Trait (
HasUserTimezone):- Automatically converts standard timestamps (
created_at,updated_at,deleted_at). - Automatically converts any custom attribute declared in Eloquent
$castsas'datetime'.
- Automatically converts standard timestamps (
- Database Persistence Safety:
- Ensures dates are always stored in UTC in your database, while presenting them in local time upon retrieval and JSON serialization.
- Global Helper Function:
user_timezone()available anywhere in your application. - API & Serialization Ready: Automatically formats dates in JSON responses for REST APIs, Filament, Inertia.js, and Blade templates.
📋 Requirements
- PHP
^8.2 - Laravel
^10.0|^11.0|^12.0
📦 Installation
Install the package via Composer:
composer require anjan-talukdar/laravel-user-timezone
Publish Configuration & Migrations
Publish the configuration file and database migration:
php artisan vendor:publish --tag="user-timezone-config"
php artisan vendor:publish --tag="user-timezone-migrations"
Run the migration to add the timezone column to your users table:
php artisan migrate
⚙️ Configuration
The published configuration file config/user-timezone.php allows you to customize the default fallback timezone and cookie name:
return [
/*
|--------------------------------------------------------------------------
| Default Timezone
|--------------------------------------------------------------------------
|
| Fallback timezone when no user or client browser timezone is detected.
|
*/
'default' => env('APP_TIMEZONE', 'Asia/Kolkata'),
/*
|--------------------------------------------------------------------------
| Cookie Name
|--------------------------------------------------------------------------
|
| The HTTP cookie key used by the frontend JS auto-detection script.
|
*/
'cookie_name' => 'user_timezone',
];
💻 Usage
1. Eloquent Model Integration
Simply add the HasUserTimezone trait to your Eloquent models:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use AnjanTalukdar\UserTimezone\Traits\HasUserTimezone;
class Post extends Model
{
use HasUserTimezone;
protected $casts = [
'published_at' => 'datetime',
'event_date' => 'datetime',
];
}
That's it! When accessing dates, they are automatically returned as Illuminate\Support\Carbon instances converted to the active user's local timezone:
$post = Post::find(1);
// Standard timestamps automatically in user's timezone
echo $post->created_at->format('Y-m-d H:i:s');
// Cast datetime attributes automatically in user's timezone
echo $post->published_at->format('M j, Y g:i A');
// Access active timezone name
echo $post->created_at->timezoneName; // e.g. "Asia/Kolkata" or "America/New_York"
2. Custom Formatting Helper Method
You can also use the model method formatUserDate() for inline formatting with custom fallback handling:
echo $post->formatUserDate('published_at', 'F j, Y, g:i a');
// Output: "July 29, 2026, 3:30 pm"
3. Global Helper Function
Access the resolved user timezone anywhere in controllers, Blade files, or services:
$currentTz = user_timezone();
// Returns e.g. "Asia/Kolkata" or "America/New_York"
4. Client-side Browser Auto-Detection
To automatically detect guest and logged-in user timezones via the browser, import the package JS snippet into your main JavaScript bundle (resources/js/app.js):
import 'path/to/packages/anjan-talukdar/laravel-user-timezone/resources/js/user-timezone.js';
Or add the standalone snippet directly in your HTML <head> or main layout:
<script>
if (!document.cookie.includes('user_timezone=')) {
const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
if (tz) {
document.cookie = "user_timezone=" + encodeURIComponent(tz) + ";path=/;max-age=31536000;SameSite=Lax";
}
}
</script>
🔍 How It Works Under the Hood
┌────────────────────────────────────────────────────────┐
│ 1. User Timezone Resolution │
│ Auth User -> Browser Cookie -> Session -> Default │
└───────────────────────────┬────────────────────────────┘
│
┌───────────────────────────▼────────────────────────────┐
│ 2. Attribute Access ($model->created_at / $casts) │
│ DB stores UTC ──► Carbon instance in User TZ │
└───────────────────────────┬────────────────────────────┘
│
┌───────────────────────────▼────────────────────────────┐
│ 3. Database Storage ($model->save()) │
│ Carbon in User TZ ──► Converted back to UTC in DB │
└────────────────────────────────────────────────────────┘
- Retrieval: When an attribute is retrieved (
created_at,updated_at,deleted_at, or any attribute cast as'datetime'),HasUserTimezoneintercepts the Carbon instance creation and applies.setTimezone(user_timezone()). - Serialization: When converting models to Array or JSON (
toArray(),toJson()), dates are formatted in the user's local timezone for API consumers. - Database Safety: When saving models, dates are converted back to UTC (or app default timezone) so your database records remain strictly synchronized and standardized in UTC.
🧪 Testing
Run package tests with PHPUnit:
vendor/bin/phpunit
📜 License
The MIT License (MIT). Please see License File for more information.
👨💻 Author
Anjan Talukdar
- GitHub: @anjan-talukdar