amidesfahani/nova-persian-date
amidesfahani/nova-persian-date adds Persian (Jalali) date support to Laravel Nova, making it easier to display and manage dates in the Persian calendar within Nova resources and admin panels for Persian-speaking users.
Install
composer require amidesfahani/nova-persian-date
This is a Nova field package, so it assumes you already have laravel/nova installed. After requiring it, publish Nova assets so the field's JS/CSS reaches the browser:
php artisan nova:publish
If the field renders but the date picker is unstyled or non-functional, that publish step (or a stale public/vendor/nova cache) is almost always the culprit.
Where to look first
Because this is a small, single-purpose package, read the source before trusting the README:
src/ — confirm the field class name and namespace (typically something like Amidesfahani\NovaPersianDate\PersianDate). This tells you which Nova base class it extends (Date, DateTime, or a custom Field).composer.json — check the laravel/nova constraint. A 2021 release likely targets Nova 3.x, so verify before dropping it into a Nova 4/5 app.resources/js/ — see which picker library is bundled (persian-date, moment-jalaali, etc.). This matters for timezone and leap-year behavior later.First use case
The canonical use is a resource field that stores Gregorian in the database but displays and accepts Jalali in the Nova UI:
use Amidesfahani\NovaPersianDate\PersianDate;
public function fields(Request $request)
{
return [
ID::make()->sortable(),
Text::make('Name'),
PersianDate::make('Birthday')
->nullable()
->rules('date'),
];
}
The column should be a normal date/datetime/timestamp column. Laravel casts it to Carbon; the field handles the visual conversion. You are not storing Jalali strings — keep the database Gregorian and let the field translate.
Start by adding it to one resource, enter a date, save, and inspect the raw DB value. If it's a Gregorian ISO date, the round-trip is working.
Standard field composition. Inherit Nova's normal field API — ->sortable(), ->nullable(), ->rules(), ->hideFromIndex(), ->help() — because it extends a Nova date field. Use these rather than assuming the package adds its own.
PersianDate::make('Subscription Ends', 'subscription_ends_at')
->sortable()
->nullable()
->rules('nullable', 'date')
->help('Enter in Jalali; stored as Gregorian.');
Keep validation Gregorian-aware. The picker submits a Gregorian-compatible value, so rules('date') and after_or_equal:today behave as normal. If you expose a Jalali string to your own API/import, convert before validation:
// Example conversion before validating
$gregorian = Jalalian::fromFormat('Y/m/d', $request->input('birthday'))->toCarbon();
Pair with standard Nova date filters. Since storage is Gregorian, Nova's built-in DateFilter and sorting work unchanged. Only build a custom filter if you want the filter UI itself to speak Jalali.
Use it for user-facing date input, not for created_at/updated_at. Auto-managed timestamps should stay hidden or display-only. Use this field where a human actually types a date: birthdays, due dates, contract dates.
Extend rather than fight it. If the package lacks withTime() / hasTime() or a default format you need, subclass the field and add it:
namespace App\Nova\Fields;
use Amidesfahani\NovaPersianDate\PersianDate;
class PersianDateTime extends PersianDate
{
public function component()
{
return 'persian-date'; // reuse the package component
}
}
Prefer a global display helper for read-only views. If most of your app needs Jalali display, don't sprinkle this field everywhere. Add a Blade directive or Carbon macro for display, and reserve the Nova field for editable date inputs.
Maintenance risk is the headline. Last release 2021-05-29, 11 stars. Treat it as unmaintained: pin the version, and confirm Nova compatibility in a branch before shipping. Nova 4+ changed field asset loading; a Nova 3 field package may render an empty input or fail to bundle.
Timezone off-by-one. Jalali conversion is timezone-sensitive. If your app timezone differs from UTC and the picker is local, a boundary date can save as the previous/next Gregorian day. Test around midnight and set app.timezone consistently.
Jalali leap years. Esfand 30 exists only in leap years. Enter Esfand 29 and 30 around a leap boundary to confirm the picker doesn't silently roll over to Farvardin 1.
Empty input. Ensure ->nullable() and validate nullable|date. An empty picker sending '' can otherwise land as 1970-01-01 or trigger a DB type error on strict datetime columns.
Sorting and search use Gregorian. Good — but don't expect ordering to follow Jalali string order. If you ever display a Jalali string column, orderBy will sort lexically, which is wrong.
Asset cache is the usual "it's broken" cause. After install or update:
php artisan nova:publish
php artisan config:clear
php artisan view:clear
Then hard-refresh the browser and check the console for a 404 on the package's JS bundle.
Debugging values. Inspect what the field actually submits in Nova's Vue devtools (network payload of the create/update request), and on the server log $model->getAttributes() after save to confirm the Gregorian value.
Have a fallback plan. If a Nova upgrade forces the issue, the practical alternatives are: fork the Vue component and port it to the current Nova field mixin, or swap to an actively maintained Jalali/persian date field. Either way, isolate the field behind one or two resources so the swap is contained.
How can I help you explore Laravel packages today?