PHPackages                             techies-africa/laravel-nomad - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. techies-africa/laravel-nomad

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

techies-africa/laravel-nomad
============================

Automatic UTC-to-user-timezone conversion for Laravel Eloquent models

1.0.3(2mo ago)0185↓33.3%MITPHPPHP &gt;=8.1

Since Jul 29Pushed 2mo agoCompare

[ Source](https://github.com/Techies-Africa/laravel-nomad)[ Packagist](https://packagist.org/packages/techies-africa/laravel-nomad)[ RSS](/packages/techies-africa-laravel-nomad/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (4)Dependencies (6)Versions (5)Used By (0)

Laravel Nomad
=============

[](#laravel-nomad)

Automatic UTC-to-user-timezone conversion for Laravel Eloquent models.

Nomad intercepts every Eloquent model as it loads from the database and converts all datetime attributes (`created_at`, `updated_at`, and any you define) from UTC to the current user's timezone. No traits, no per-model configuration. It works globally, out of the box.

How It Works
------------

[](#how-it-works)

1. Your database stores all datetimes in UTC (the Laravel default).
2. Nomad detects the user's timezone from: HTTP header, session, authenticated user's DB column, GeoIP, or config fallback.
3. When a model is retrieved, Nomad dynamically applies a custom Eloquent cast to every datetime column, converting UTC to the user's timezone.
4. When you save a model, the cast converts any timezone-aware Carbon instance back to UTC before writing to the database.

You read in local time. You write in UTC. Automatically.

Requirements
------------

[](#requirements)

- PHP &gt;= 8.1
- Laravel 10.x, 11.x, or 12.x

Installation
------------

[](#installation)

```
composer require techies-africa/laravel-nomad
```

Run the install command to publish the config file and migration:

```
php artisan nomad:install
```

Run the migration to add a `timezone` column to your users table:

```
php artisan migrate
```

### Register the Middleware

[](#register-the-middleware)

Add the Nomad middleware to your application. The middleware detects the user's timezone on each request and persists it to the database for authenticated users (only when the timezone changes).

**Laravel 11/12** (`bootstrap/app.php`):

```
->withMiddleware(function (Middleware $middleware) {
    $middleware->append(\TechiesAfrica\Nomad\Middleware\NomadMiddleware::class);
})
```

**Laravel 10** (`app/Http/Kernel.php`):

```
protected $middleware = [
    // ...
    \TechiesAfrica\Nomad\Middleware\NomadMiddleware::class,
];
```

If you need to customize the middleware, publish a local copy and reference that instead:

```
php artisan vendor:publish --tag=nomad-middleware
```

This publishes to `app/Http/Middleware/Nomad/NomadMiddleware.php`.

### Frontend: Sending the Timezone Header

[](#frontend-sending-the-timezone-header)

For Nomad to detect the user's timezone, your frontend should send an `X-Timezone` header with every request. The browser's `Intl` API provides this:

```
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
// "America/New_York", "Africa/Lagos", "Asia/Tokyo", etc.
```

**With Axios:**

```
axios.defaults.headers.common['X-Timezone'] =
    Intl.DateTimeFormat().resolvedOptions().timeZone;
```

**With Fetch:**

```
fetch('/api/endpoint', {
    headers: {
        'X-Timezone': Intl.DateTimeFormat().resolvedOptions().timeZone,
    },
});
```

Usage
-----

[](#usage)

Once installed, Nomad works automatically. There is nothing to add to your models.

```
// Database stores: 2024-06-15 10:00:00 (UTC)
// User's timezone: Africa/Lagos (UTC+1)

$post = Post::find(1);

$post->created_at;          // 2024-06-15 11:00:00 Africa/Lagos
$post->created_at->hour;    // 11
$post->created_at->timezone; // Africa/Lagos

// Saving converts back to UTC automatically
$post->published_at = now(); // Carbon instance in any timezone
$post->save();               // Stored as UTC in the database
```

### Excluding Models

[](#excluding-models)

If certain models should not have timezone conversion (e.g., audit logs that must stay in UTC):

```
// config/nomad.php

'excluded_models' => [
    \App\Models\AuditLog::class,
    \App\Models\SystemEvent::class,
],
```

### Disabling Globally

[](#disabling-globally)

To disable all timezone conversion without removing the package:

```
// config/nomad.php

'enabled' => false,
```

Timezone Detection
------------------

[](#timezone-detection)

Nomad resolves the user's timezone through a fallback chain. The first valid result wins:

PrioritySourceDescription1HTTP Header`X-Timezone` header sent by the frontend2SessionTimezone stored in session from a previous request3DatabaseAuthenticated user's `timezone` column4GeoIPIP-based lookup (optional, requires `torann/geoip`)5Config`nomad.default_output_timezone` value6App timezone`config('app.timezone')`, typically UTC### GeoIP Fallback (Optional)

[](#geoip-fallback-optional)

To enable IP-based timezone detection as a fallback:

```
composer require torann/geoip
```

```
// config/nomad.php

'geoip' => [
    'enabled' => true,
],
```

Configuration
-------------

[](#configuration)

Publish the config file (done automatically by `nomad:install`):

```
php artisan vendor:publish --tag=nomad-config
```

Full config reference (`config/nomad.php`):

```
return [
    // Master switch to enable/disable timezone conversion
    'enabled' => true,

    // Database table that stores user timezones
    'table' => 'users',

    // Column name for the timezone string
    'column' => 'timezone',

    // Auth guard (null = default guard)
    'guard' => null,

    // Models excluded from timezone conversion
    'excluded_models' => [],

    // Fallback timezone when no user timezone is available
    'default_output_timezone' => env('NOMAD_OUTPUT_TIMEZONE'),

    // HTTP header name for frontend timezone detection
    'header' => 'X-Timezone',

    // Session key for persisting detected timezone
    'session_key' => 'nomad_timezone',

    // GeoIP configuration
    'geoip' => [
        'enabled' => false,
    ],
];
```

Artisan Commands
----------------

[](#artisan-commands)

CommandDescription`php artisan nomad:install`Publishes config and migration`php artisan nomad:uninstall`Removes published config, migration, and middleware files`php artisan nomad:migrate`Publishes and runs the timezone migrationArchitecture
------------

[](#architecture)

Nomad uses three core components:

**NomadDatetimeCast** - A Laravel custom cast (`CastsAttributes`). On `get()`: parses the raw UTC value and returns a Carbon instance in the user's timezone. On `set()`: converts any Carbon/DateTime instance back to a UTC string.

**NomadTimezoneObserver** - Listens to wildcard Eloquent events (`eloquent.retrieved: *` and `eloquent.created: *`). When any model is loaded, it discovers all datetime columns and dynamically applies `NomadDatetimeCast` via `$model->mergeCasts()`.

**NomadTimezoneResolver** - A request-scoped singleton that resolves the user's timezone through the fallback chain described above. The result is cached for the duration of the request.

This design means:

- No traits or interfaces to add to your models
- No dirty-state issues (raw database attributes are never modified by the observer)
- `isDirty()`, `toArray()`, `toJson()`, and `getOriginal()` all work correctly
- Standard Laravel pattern using documented Eloquent APIs

Testing
-------

[](#testing)

```
composer test
```

Uninstalling
------------

[](#uninstalling)

```
php artisan nomad:uninstall
composer remove techies-africa/laravel-nomad
```

Credits
-------

[](#credits)

- **Author**: [Joel Omojefe](https://www.linkedin.com/in/joel-omojefe/)
- **Organization**: [Techies Africa](https://techies.africa)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE) for more information.

###  Health Score

41

—

FairBetter than 89% of packages

Maintenance82

Actively maintained with recent releases

Popularity15

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity51

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~187 days

Total

4

Last Release

89d ago

PHP version history (2 changes)1.0.0PHP &gt;=7.0

1.0.2PHP &gt;=8.1

### Community

Maintainers

![](https://www.gravatar.com/avatar/987c235264b37ea3f3f1f56a592045e9d6d63f4f0809cfb3c8818cbd3241f32a?d=identicon)[Confidence1851](/maintainers/Confidence1851)

---

Top Contributors

[![Joelomojefe](https://avatars.githubusercontent.com/u/90783308?v=4)](https://github.com/Joelomojefe "Joelomojefe (19 commits)")

---

Tags

laraveldatetimetimedatetimezoneutctechies-africanomadlaravel-nomad

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/techies-africa-laravel-nomad/health.svg)

```
[![Health](https://phpackages.com/badges/techies-africa-laravel-nomad/health.svg)](https://phpackages.com/packages/techies-africa-laravel-nomad)
```

###  Alternatives

[brick/date-time

Date and time library

3623.3M61](/packages/brick-date-time)[dater/dater

Compact PHP library for working with date/time in different formats &amp; timezones.

14282.3k](/packages/dater-dater)[whitecube/laravel-timezones

Store UTC dates in the database and work with custom timezones in the application.

106106.2k](/packages/whitecube-laravel-timezones)[fresh/datetime

PHP library that provides additional functions for processing dates &amp; times.

17513.8k2](/packages/fresh-datetime)[p3ym4n/jdate

Date converter from Jalali to Georgian and vice versa. It has Carbon instance inside and it's Laravel friendly.

101.8k2](/packages/p3ym4n-jdate)[maherelgamil/arabicdatetime

Easy and useful tool to generate arabic or hijri date with multi-language support for laravel

414.5k](/packages/maherelgamil-arabicdatetime)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
