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

Filament Jalali Datetime Laravel Package

ariaieboy/filament-jalali-datetime

Adds Persian (Jalali/Shamsi) date and time pickers to Filament forms and tables. The plugin offers ready-to-use Jalali date picker components, accurate Gregorian–Jalali conversion, and localized Persian formatting so admin panels can accept and display dates in the Iranian calendar.

View on GitHub
Deep Wiki
Context7

Getting Started

ariaieboy/filament-jalali-datetime is a Filament form-field plugin that swaps Filament's Gregorian date/time pickers for Jalali (Shamsi) equivalents while still persisting standard Gregorian values to your database.

Minimal setup:

composer require ariaieboy/filament-jalali-datetime
php artisan vendor:publish --tag="filament-jalali-datetime-config"   # optional

Then use the Jalali fields in place of Filament's native pickers:

use Ariaieboy\FilamentJalaliDatetime\JalaliDatePicker;
use Ariaieboy\FilamentJalaliDatetime\JalaliDateTimePicker;
use Ariaieboy\FilamentJalaliDatetime\JalaliTimePicker;

JalaliDatePicker::make('birth_date'),
JalaliDateTimePicker::make('published_at')->seconds(false),
JalaliTimePicker::make('opens_at'),

Where to look first:

  1. The published config file — it holds the default display formats and locale/timezone knobs you'll almost certainly need to align with your app.
  2. The package source for each component (they extend Filament's DateTimePicker/DatePicker), so anything you know from Filament's fluent API (minDate(), maxDate(), seconds(), displayFormat(), timezone(), disabledDates(), reactive ->live()) still applies.
  3. Your migration column types — the plugin handles display, not storage. First use case: an orders or posts resource where an admin in Tehran needs to pick a publish date and read it back in Shamsi, while created_at/published_at remain Gregorian datetime columns in MySQL.

First useful thing to build: take an existing resource form, replace one DateTimePicker with JalaliDateTimePicker, save a record, and confirm the DB row is Gregorian and the re-rendered form is Jalali. That round-trip is the whole value proposition — verify it before rolling out everywhere.

Implementation Patterns

Drop-in replacement on forms. The components are subclasses, so a Jalali field accepts the same fluent chain as Filament's own. Migration pattern: change the use statement and the class name, keep the rest of the chain, test the round-trip. This makes incremental adoption in a large codebase low-risk.

Table columns and filters stay partly manual. The package targets form fields; for tables you'll typically use TextColumn::make('published_at')->formatStateUsing(...) with a Jalali conversion, or the dateTime() formatting helpers, since the picker components don't render table cells. Pair the field with a table column that formats the same raw Gregorian value into Shamsi, and keep the two format strings in one config/helper so they never drift.

Keep conversion in one place. For exports, PDFs, notifications and API resources you'll want a single Jalali helper (or a small casts/accessor) rather than sprinkling conversion logic. A common pattern is a HasJalaliDates trait on models exposing getPublishedAtJalaliAttribute() used by mail templates and Blade views, while the picker handles input.

Reactive dashboards. Because the fields are Livewire-bound like any Filament component, ->live() + ->afterStateUpdated() works normally. Useful for "select Jalali date → show weekday name / holiday warning" UX that Persian users expect.

Validation and cross-field rules. Combine with ->rules(['after_or_equal:today']) carefully: Laravel validates the state value. Confirm whether the component stores a Gregorian string in state (usual) or a Jalali string, then write rules against that representation. For ranges (starts_at / ends_at), validate in Gregorian and only localise labels.

Multi-panel / multi-locale apps. If one panel is Persian-only and another is English-only, guard field selection behind a helper like isJalaliPanel() rather than duplicating resources — swapping the field class at runtime in form() is cheap and keeps a single schema definition.

Gotchas and Tips

  • Timezone is the classic trap. A picker set to Asia/Tehran plus an app on UTC plus a DB column without timezone awareness can shift dates by a day near midnight. Set the field's timezone() deliberately and decide whether users pick in local time. Store UTC, display Tehran, and write a test that saves 23:30 local and asserts the stored value.
  • Jalali leap years and month lengths differ. 1403/12/30 exists or not depending on the year and no Carbon shortcut saves you — don't hand-roll +1 month arithmetic on Jalali strings; convert to Carbon, manipulate, convert back.
  • Storage format. Confirm whether the component writes Y-m-d H:i:s or an ISO string into state before it hits your model cast. If you have 'published_at' => 'datetime' casts, an unexpected format will throw on save — reproduce in a test with a real SQLite/MySQL column, not just a Livewire component test.
  • Config cache. After publishing or editing the config, run php artisan config:clear; Filament panels under config:cache in production will silently keep old formats. This is the first thing to check when "the format didn't change".
  • Upgrading Filament. Because the fields extend Filament internals, a Filament major bump can break them even when this package's version is unchanged. Pin Filament and this package together in composer.json, and read this package's changelog for supported Filament majors after any Filament upgrade.
  • PHP 8.4 (new in 1.4.2). This release only widens the Composer constraint to allow PHP 8.4 — no API or behavioural changes. It's a safe drop-in from 1.4.1; the practical benefit is that you can now run this package on an 8.4 runtime without --ignore-platform-req. If you're still on 8.1–8.3 nothing changes for you.
  • Debugging display issues. Isolate the layer: log the raw state in afterStateUpdated(), then check the model attribute after save, then the formatted output. The bug is nearly always in one of those three, and knowing which one halves the fix time.
  • Extension point. If a required feature is missing (e.g. a Persian calendar popover style, or a specific holiday-disabling rule), subclass the field and override the view/getView() or the format method rather than editing vendor code — the package's views are publishable/taggable, and subclasses survive composer update.
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
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
cgv/localized-resource