Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Intl Date Time Laravel Package

techouse/intl-date-time

Locale-aware date and time formatting for Laravel powered by PHP's Intl extension. Provides Carbon macros, Blade directives, validation rules, and easy localization of dates across your app, with dozens of locales supported out of the box. Simple to configure and use.

View on GitHub
Deep Wiki
Context7

Getting Started

Two preconditions gate everything: a Laravel Nova license (this is a Nova field, not a general Laravel date helper) and the PHP Intl extension (ext-intl), since all locale rendering runs through ICU. If either is missing, stop — there is no salvageable headless surface here.

composer require techouse/intl-date-time

Then read these three things before writing code, in this order:

  1. vendor/techouse/intl-date-time/composer.json — the nova, php, and laravel/framework constraints. The package is archived, so those constraints are frozen; nobody upstream will widen them for your Nova major.
  2. The field class in src/ — its make() signature, which IntlDateFormatter style/pattern options it exposes, and whether resolve()/fill() normalize the value before it reaches your model. Also check whether the Carbon macros and Blade directives advertised in the README actually ship, or whether the Nova field is the only real surface.
  3. dist/js/field.js — glance at the bundle header. Mix/Vue 2 vs. Vite/Vue 3 is the single detail that predicts whether the field loads on your Nova version.

First use case: one Nova resource backed by an existing datetime column, used by an editor whose locale is not en-US. Do not start with a greenfield column.

use Techouse\IntlDateTime\IntlDateTime;

public function fields(Request $request)
{
    return [
        IntlDateTime::make('Published At')
            ->rules('required', 'date')
            ->sortable(),
    ];
}

Then run the only test that matters before committing: create a record, save, reload the edit form, and confirm the value round-trips without drift. If that fails on your Nova major, stop and build the thin owned field instead — Flatpickr + Intl.DateTimeFormat, ~150–300 lines, comparable effort and far less lifecycle risk.

Implementation Patterns

Adopt per-field, never globally. The field is declarative and stateless — no migration, no config publish, no queue, no service provider work beyond Nova's asset registration. Roll it onto one resource, watch it for a sprint, then expand. Keeping it off your highest-traffic admin screens limits blast radius when a Nova upgrade breaks it.

Separate display locale from storage format. The picker renders in the user's locale; the column persists ISO-8601/UTC. Verify by inspecting the raw request payload after a save — do not assume.

// Model: keep the cast, keep UTC in the column
protected $casts = ['published_at' => 'datetime'];

// Locale and timezone come from the user, not from config
'locale' => fn () => auth()->user()?->locale ?? config('app.locale'),
'timezone' => fn () => auth()->user()?->timezone ?? config('app.timezone'),
// FormRequest: validate the server, never the rendered string
'published_at' => ['required', 'date_format:Y-m-d\TH:i:s\Z'],

Wrap it in your own field class. Highest-leverage pattern for an archived dependency — it gives you a one-line swap point later.

namespace App\Nova\Fields;

use Techouse\IntlDateTime\IntlDateTime;

class LocalizedDateTime extends IntlDateTime
{
    public function component()
    {
        return 'localized-date-time'; // your published/owned Vue component
    }
}

Every resource then references LocalizedDateTime, and replacing the implementation touches one file.

Fork-and-own once the spike passes. Consume via a VCS repository entry rather than Packagist, tag it, rebuild assets under your own toolchain, and add a smoke test asserting a save/load round-trip.

"repositories": [{"type": "vcs", "url": "[email protected]:acme/nova-intl-datetime.git"}],
"require": {"acme/nova-intl-datetime": "^1.0"}

Pin expectations in browser tests, not in your head. Locale rendering depends on the client's ICU data, so a Dusk/Playwright assertion on the rendered input string is worth more than a PHP unit test. Pair it with a server-side assertion on what actually lands in the column.

Use it as a reference implementation even if you don't ship it. MIT-licensed, one field class plus a Vue component — reading the source is often faster than evaluating alternatives and will sharpen your estimate for the owned build.

Gotchas and Tips

  • Archived means you are the maintainer. No security patches, no Nova-major tracking. Budget roughly half a day per Nova major plus ad hoc Vue/picker bumps, and put it on a maintained-dependency watchlist with a named owner.
  • Asset pipeline mismatch is the most likely failure. Nova 4/5 moved to Vite-built Vue 3; fields of this vintage are frequently Mix/Vue 2. The failure mode is silent — the field degrades to a plain text input and nobody notices until bad data arrives. Add a browser-level smoke test.
  • Never trust the client's formatted value. A locale picker is presentation. Server-side date/date_format rules plus a datetime cast are non-negotiable; without them you will persist 03/04 verbatim.
  • Off-by-one-day around midnight and DST is the classic symptom of a localized display string leaking into storage. Store UTC, render in the user's timezone, and assert it in a test with a non-UTC APP_TIMEZONE.
  • Ambiguous entry is reduced, not eliminated. A locale-aware picker fixes DD/MM vs. MM/DD ordering; it does nothing for ranges, recurrence, business-day rules, or "is this date in the past in the user's timezone?"
  • CI browsers may lack full ICU data. Headless Chromium builds can fall back to a default format, so pin Node/browser versions and assert exact rendered strings.
  • Debug by reading source, not searching the web. With 57 stars, zero dependents, and an archived repo, there is no community safety net. grep the field class and the compiled bundle.
  • Extension points are limited to the field class and the Vue component. If you need behavior beyond the exposed formatting options, override resolve(), fill(), or component() in your subclass — that is the whole surface area.
  • Document locale and storage conventions in the repo. Without a short README note, the field becomes tribal knowledge and a bus-factor risk on the next upgrade.
  • Runtime cost is nil — one input plus an Intl call. Do not profile; spend that time on the ownership plan.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect