همونطور که میدونید لاراول برای هندل کردن تاریخ و زمان بطور پیشفرض از پکیج انصافا قدرتمند Carbon استفاده میکنه و اتریبیوتهای از نوع زمان مدلها رو بصورت خودکار به اینستنس کربن تبدیل میکنه. همین قضیه باعث میشه دست برنامهنویس برای کار با اتریبیوتهای از نوع زمان تو مدلهای لاراول نسبتا باز باشه و بتونه از دهها متدی که کربن در اختیارش میذاره به راحتی استفاده کنه.
$user->created_at->format('j F Y') // 12 February 2021 $user->created_at->subDays(5)->format('j F Y') // 7 February 2021 $user->created_at->isoFormat('D MMMM YYYY') // 7 February 2021 $user->created_at->diffForHumans() // 5 days ago $user->created_at->isPast() // true
ولی این راحتی فقط تا وقتیه که بخواهید از اختلاف زمانی یا عقب و جلو بردن زمان و یا تاریخ میلادی استفاده کنید و وقتی صحبت از تاریخ شمسی میشه کار زیادی از دست کربن برنمیاد. هر چند کربن امکان localization داره و میشه fa_IR رو به عنوان locale بهش داد. ولی این کار صرفا خروجیهای متنی کربن رو به فارسی ترجمه میکنه و نوع تاریخ همچنان میلادی باقی میمونه.
Carbon::setLocale('fa_IR') $user->created_at->format('j F Y') // 12 February 2021 $user->created_at->subDays(5)->format('j F Y') // 7 February 2021 $user->created_at->isoFormat('D MMMM YYYY') // 7 فوریه 2021 $user->created_at->diffForHumans() // 5 روز پیش $user->created_at->isPast() // true
حالا با این اوصاف چطور میشه از تاریخ شمسی تو لاراول استفاده کرد؟ مشخصا برای این سوال جواب قطعیای وجود نداره و هر برنامهنویسی بنا به شرایط پروژهاش یه راهی واسه این کار پیدا میکنه. بعضیها استفاده از پکیج Morilog/jalali رو توصیه میکنن، بعضیها همچنان از کتابخونه jdf.php (چه به شکل Helper function و چه با تبدیلش به کلاس) استفاده میکنن و اخیرا هم خیلیها به استفاده از پکیج Verta رو آوردن و البته دهها راه حل و روش دیگه که هر کسی بنا به انتخابش ممکنه ازش استفاده کنه یا نکنه.
\Morilog\Jalali\Jalalian::fromCarbon($user->created_at)->format('%e %B %Y') // 24 بهمن 1399 jdate('j F Y', $user->created_at->timestamp) // ۲۴ بهمن ۱۳۹۹ \App\Http\Helpers\JDate::jdate('j F Y', $user->created_at->timestamp) // ۲۴ بهمن ۱۳۹۹ verta($user->created_at)->format('%e %B %Y') // 24 بهمن 1399
ولی چیزی که درباره روشهای بالا برای من غیرقابل قبوله – البته علاوه بر اینکه به نظر من تو عمل با روح لاراول یعنی رسیدن به نتیجه با حداقل مقدار کد در تضادن – اینه که توشون کربن با همه توانمندیهاش دور زده میشه و عملا کنار گذاشته میشه. مثلا پکیج ورتا درسته خیلی کامل و قویه و مخصوصا ابزارهای خوبی تو بحث اعتبارسنجی داره، ولی خب کربن که بود چه کاریه چرخ دوباره اختراع شه؟
پیشنهاد من بجای کنار گذاشتن کربن، گسترشش برای پشتیانی از تاریخ شمسیه. همونطور که میدونید کربن متدی داره به اسم macro که مثل بقیه متدهای ماکرو پکیجهای دیگه کارش امکان اضافه کردن متد و اتریبیوت سفارشی به کلاسه. از طرف دیگه هم کتابخونه jdf.php رو داریم که یکی از سادهترین ابزارهای کار با تاریخ شمسی تو دنیای پیاچپیه و اگه قبلا باهاش کار نکردین تو کمتر از ۱۰ دقیقه میتونید همه داکیومنتشو بخونید. خب حالا چی میشه اگه این دوتا رو هم ترکیب کنیم:
Carbon::macro('jdate', function ($format, $tr_num = 'fa') { return jdate($format, self::this()->timestamp, '', '', $tr_num); }); Carbon::macro('jmktime', function ($year, $month, $day, $hour = 0, $minute = 0, $second = 0) { $timestamp = jmktime($hour, $minute, $second, $month, $day, $year); return self::createFromTimestamp($timestamp); });
به همین سادگی و بدون مسآپ دو تا متد jdate و jmktime رو به کربن اضافه کردیم که کار اولی چاپ خروجی تاریخ شمسی و کار دومی ایجاد اینستنس کربن از تاریخ شمسیه. تازه کربن و امکانتش هم موند سر جاش.
$user->created_at->jdate('j F Y') // ۲۴ بهمن ۱۳۹۹ Carbon::jmktime(1399, 11, 24)->subDays(5)->jdate('j F Y') // ۱۹ بهمن ۱۳۹۹ Carbon::jmktime(1399, 11, 24)->subDays(5)->isPast() // true
حالا فقط باید کاری کنیم که کدمون تو شروع برنامه اجرا شه که بشه از این متدها تو همه جای پروژه کرد. برای این کار میتونید کد رو تو متد boot سرویس پروایدر AppServiceProvider بذارید یا حتی برای تمیزتر شدن کار یه سرویس پروایدر جدید به اسم مثلا CarbonServiceProvider ایجاد کنید و کد رو تو متد boot اون بذارید:
<?php namespace App\Providers; use Carbon\Carbon; use Illuminate\Support\ServiceProvider; class CarbonServiceProvider extends ServiceProvider { /** * Register services. */ public function register() { // } /** * Bootstrap services. */ public function boot() { Carbon::setLocale('fa_IR'); Carbon::macro('jdate', function ($format, $tr_num = 'fa') { return jdate($format, self::this()->timestamp, '', '', $tr_num); }); Carbon::macro('jmktime', function ($year, $month, $day, $hour = 0, $minute = 0, $second = 0) { $timestamp = jmktime($hour, $minute, $second, $month, $day, $year); return self::createFromTimestamp($timestamp); }); } }
مشخصا من بصورت دلخواه اسم متدهای جدید رو jdate و jmktime گذاشتم و ترتیب آرگومانهای ورودی رو عوض کردم، شما میتونید هر اسمی که خواستید (مثل formatJalali و createJalali) و با هر ترتیب آرگومانی که خواستید رو تعیین کنید. همین طور بدیهیه که با استفاده از متد macro کربن میتونید هر چقدر متد و اتریبیوت سفارشی که خواستید به کربن اضافه کنید و صد البته مسلمه که میتونید داخل ماکرو برای تبدیل تاریخ بجای jdf.php که من استفاده کردم از ابزارهای دیگه مثل خود ورتا استفاده کنید که جاهای دیگه پروژه امکانات دیگه مثل اعتبارسنجی اون رو هم داشته باشید.
A Simple way to work with Jalali date in Laravel using Carbon and jdf.php