hekmatinasser/jalali
Jalali (Shamsi) date/time utilities for PHP and Laravel. Converts between Jalali (solar) and Gregorian calendars, provides helper functions for formatting and working with dates. Extends PHP DateTime and is compatible with Carbon.
Installation:
composer require hekmatinasser/jalali
Add the service provider to config/app.php:
'providers' => [
// ...
Hekmatinasser\Jalali\JalalianServiceProvider::class,
],
Publish Config (Optional):
php artisan vendor:publish --provider="Hekmatinasser\Jalali\JalalianServiceProvider"
This generates config/jalali.php for customization (e.g., default locale, timezone).
First Use Case:
Convert a Gregorian DateTime to Jalali:
use Hekmatinasser\Jalali\Jalalian;
$gregorian = new \DateTime('2023-12-25');
$jalali = Jalalian::fromGregorian($gregorian);
echo $jalali->format('Y/m/d'); // Output: 1402/10/04
Carbon Integration:
use Carbon\Carbon;
use Hekmatinasser\Jalali\Jalalian;
$carbon = Carbon::parse('2023-12-25');
$jalaliCarbon = Jalalian::fromCarbon($carbon);
echo $jalaliCarbon->format('Y/m/d'); // Output: 1402/10/04
Date Conversion:
$jalali = Jalalian::fromGregorian($gregorianDateTime);
$gregorian = Jalalian::fromJalali($jalaliDateTime);
$jalaliCarbon = Jalalian::fromCarbon($carbon);
$gregorianCarbon = Jalalian::toCarbon($jalaliCarbon);
Formatting:
Use Jalali’s built-in formatters (supports all PHP DateTime formatters + Jalali-specific ones):
$jalali->format('l j F Y'); // e.g., "شنبه ۴ آبان ۱۴۰۲"
$jalali->format('Y/m/d H:i'); // e.g., "1402/10/04 12:30"
Query Builder Integration: Use with Laravel’s query builder for Jalali-aware timestamps:
use Hekmatinasser\Jalali\Jalalian;
$jalaliDate = Jalalian::fromFormat('Y/m/d', '1402/10/04');
$gregorianDate = $jalaliDate->toGregorian();
// Store Jalali date as Gregorian in DB (recommended for consistency)
DB::table('events')->whereDate('created_at', $gregorianDate)->get();
Helper Functions:
$nowJalali = Jalalian::now();
$jalali = Jalalian::fromFormat('d/m/Y', '04/10/1402');
Timezone Handling:
Set default timezone in config/jalali.php (e.g., Asia/Tehran) to avoid manual conversions:
'timezone' => 'Asia/Tehran',
Custom Formatters: Extend the package to add Jalali-specific formatters (e.g., Persian month names):
Jalalian::addFormat('F', function($date) {
$months = ['فروردین', 'اردیبهشت', /* ... */];
return $months[$date->format('n') - 1];
});
Middleware for Jalali Responses: Convert all responses to Jalali dates in API:
namespace App\Http\Middleware;
use Hekmatinasser\Jalali\Jalalian;
use Closure;
class ConvertJalaliDates
{
public function handle($request, Closure $next)
{
$response = $next($request);
$response->getContent();
$response->setContent(
preg_replace_callback(
'/"(\d{4}-\d{2}-\d{2})"/',
fn($matches) => '"' . Jalalian::fromFormat('Y-m-d', $matches[1])->format('Y/m/d') . '"',
$response->getContent()
)
);
return $response;
}
}
Model Observers: Automatically convert timestamps to/from Jalali:
use Hekmatinasser\Jalali\Jalalian;
use Illuminate\Database\Eloquent\Model;
class Event extends Model
{
protected $dates = ['created_at', 'updated_at'];
public function getCreatedAtAttribute($value)
{
return Jalalian::fromGregorian($value)->format('Y/m/d H:i');
}
public function setCreatedAtAttribute($value)
{
$this->attributes['created_at'] = Jalalian::fromFormat('Y/m/d H:i', $value)->toGregorian();
}
}
Validation: Validate Jalali dates in Laravel:
use Hekmatinasser\Jalali\Jalalian;
use Illuminate\Support\Facades\Validator;
$validator = Validator::make($request->all(), [
'event_date' => [
'required',
function ($attribute, $value, $fail) {
if (!Jalalian::isValid($value)) {
$fail('The ' . $attribute . ' is invalid.');
}
},
],
]);
Database Storage:
toGregorian()) before saving to ensure consistency.// ❌ Bad: Storing Jalali directly
$model->date = Jalalian::now()->format('Y/m/d');
// ✅ Good: Store Gregorian, convert on retrieval
$model->date = Jalalian::now()->toGregorian();
Timezone Mismatches:
Asia/Tehran) matches the expected Jalali calculations.Jalalian::setTimezone('Asia/Tehran');
Carbon vs. Native DateTime:
DateTime and Carbon. Prefer Carbon for Laravel apps to avoid quirks with native DateTime immutability.$jalali = Jalalian::fromGregorian($gregorian);
$jalali->modify('+1 day'); // Works with Carbon; may behave unexpectedly with native DateTime.
Leap Year Calculations:
$leapYear = Jalalian::fromFormat('Y', '1404');
$leapYear->modify('+1 year'); // Should correctly roll over to 1405.
Locale-Specific Formatting:
voku/helpertypes or symfony/intl for advanced localization.Validate Jalali Dates:
Use Jalalian::isValid() to check if a Jalali string is correct:
if (!Jalalian::isValid('1402/13/04')) {
// Invalid: Month 13 doesn't exist in Jalali.
}
Compare Dates: Convert both dates to Gregorian before comparison:
$jalali1 = Jalalian::fromFormat('Y/m/d', '1402/10/04');
$jalali2 = Jalalian::fromFormat('Y/m/d', '1402/10/05');
if ($jalali1->toGregorian() < $jalali2->toGregorian()) {
// jalali1 is earlier.
}
Log Raw Data: Log Gregorian timestamps alongside Jalali for debugging:
$jalali = Jalalian::now();
\Log::debug([
'jalali' => $jalali->format('Y/m/d'),
'gregorian' => $jalali->toGregor
How can I help you explore Laravel packages today?