همهی راهنماها
راهنمایی با این جستوجو پیدا نشد.
تبدیل و مقایسهٔ تاریخها
قرارداد مشترک CalendarDate در Jalali و Hijri و Hebrew، تبدیل تاریخ بین تقویمها، و مقایسه و اختلاف بین تقویمها و منطقههای زمانی مختلف.
در این صفحه
یک لحظه، سه تقویم
سه کلاس تقویم (جلالی، هجری و عبری) یک طراحی دارند. هر کدام فقط یک لحظه (DateTimeImmutable) نگه میدارد و آن را با تقویم خودش نشان میدهد. پس تبدیل بین تقویمها از متن رد نمیشود. همان لحظه است که با قاعدهای دیگر خوانده میشود. دو نتیجه دارد:
- اگر تاریخی را تبدیل کنید و برگردانید، همان لحظهٔ اول را میگیرید.
- مقایسه و تفریقِ تاریخهای تقویمهای مختلف همیشه معنا دارد، چون لحظهها مقایسه میشوند.
مثالها با این چند خط شروع میشوند:
<?php
require 'vendor/autoload.php';
use RtlyKit\Calendar\Hebrew;
use RtlyKit\Calendar\Hijri;
use RtlyKit\Calendar\Jalali;
use RtlyKit\Contracts\CalendarDate;
use RtlyKit\Exceptions\InvalidDateException;
$utc = new DateTimeZone('UTC');تبدیل بین تقویمها
تاریخ را به make() کلاس دیگر بدهید
هر make() یک CalendarDate قبول میکند (و DateTimeInterface، زمان یونیکس، رشته یا null هم قبول میکند). تاریخی را که دارید به کلاسِ تقویم مقصد بدهید:
$j = Jalali::create(1405, 1, 1, 12, 0, 0, $utc);
echo Hijri::make($j)->format('Y/m/d F', 'en'); // 1447/10/02 Shawwal
echo Hebrew::make($j)->format('Y/m/d F'); // 5786/07/03 Nisan
echo Jalali::make(Hijri::make($j)); // 1405/01/01 12:00:00ساعت و منطقهٔ زمانی همراه تاریخ میآیند. اگر نتیجه را در منطقهٔ دیگری میخواهید، DateTimeZone را آرگومان دوم make() بدهید:
$tehran = new DateTimeZone('Asia/Tehran');
$h = Hijri::make($j, $tehran);
echo $h->getTimezone()->getName(); // Asia/Tehran
echo $h->getHour(), ':', $h->getMinute(); // 15:30 (ساعت 12:00 UTC)میانبر برای همکلاس. Hijri::make($hijri) و Hebrew::make($hebrew) همان شیئی را که دادهاید برمیگردانند (منطقهٔ زمانی یا گونه نادیده گرفته میشود). Jalali::make($jalali) هم همینطور است، مگر اینکه منطقه بدهید. آنوقت نسخهای در آن منطقه میگیرید. برای عوض کردن گونهٔ یک تاریخ هجری از لحظه شروع کنید: Hijri::make($h->toGregorian(), null, HijriVariant::Tabular).
از میلادی و به میلادی
متد toGregorian() همان DateTimeImmutable زیرین را میدهد. برای مسیر برعکس، DateTimeInterface را به make() بدهید. تبدیلهای استاتیک هم روی عدد ساده کار میکنند:
$g = new DateTimeImmutable('2026-03-21 12:00', $utc);
echo json_encode([
Jalali::gregorianToJalali(2026, 3, 21),
Hijri::gregorianToHijri(2026, 3, 21),
Hebrew::gregorianToHebrew(2026, 3, 21),
]);
// [[1405,1,1],[1447,10,2],[5786,7,3]]
echo json_encode(Jalali::jalaliToGregorian(1405, 1, 1)); // [2026,3,21]
echo get_class($j->toGregorian()); // DateTimeImmutableسال میلادی باید بین ۱ و ۹۹۹۹ باشد. بازهٔ هر تقویم (جلالی -۶۲۰ تا ۹۳۷۷، هجری ۱ تا ۹۶۶۵، عبری ۳۷۶۲ تا ۱۳۷۵۹) بخشی از همین بازه است. برای همین ممکن است تاریخ میلادیِ قدیمی را نتوان به عبری یا هجری برد. در این حالت InvalidDateException میگیرید، حتی اگر خود تاریخ میلادی درست باشد:
try { Hebrew::make(new DateTimeImmutable('0001-01-01', $utc)); }
catch (InvalidDateException $e) { echo $e->getMessage(); }
// Date out of the supported Hebrew range (3762..13759): 3761منطقهٔ زمانی تاریخ را عوض میکند
تاریخ تقویمیِ یک لحظه به منطقهای بستگی دارد که از آن نگاه میکنید. این لحظه در UTC هنوز اول فروردین ۱۴۰۵ (۲۱ مارس) است، ولی در تهران که ۳٫۵ ساعت جلوتر است، دوم فروردین شده:
$instant = new DateTimeImmutable('2026-03-21 22:30', $utc);
echo Jalali::make($instant); // 1405/01/01 22:30:00 (UTC)
echo Jalali::make($instant, $tehran); // 1405/01/02 02:00:00 (تهران، +03:30)هر جا روز تقویمی مهم است، منطقه را صریح بدهید و به پیشفرض سرور تکیه نکنید.
قرارداد CalendarDate
RtlyKit\Contracts\CalendarDate یک اینترفیس است که Stringable را گسترش میدهد. Jalali، Hijri و Hebrew آن را پیاده میکنند. اگر میخواهید کدی بنویسید که با هر تقویمی کار کند، همین نوع را تایپهینت کنید:
function describe(CalendarDate $d): string
{
return sprintf('%s %d/%02d/%02d', (new ReflectionClass($d))->getShortName(),
$d->getYear(), $d->getMonth(), $d->getDay());
}
foreach ([Jalali::class, Hijri::class, Hebrew::class] as $class) {
echo describe($class::make($g)), "\n";
}
// Jalali 1405/01/01
// Hijri 1447/10/02
// Hebrew 5786/07/03| گروه | اعضا |
|---|---|
| ساخت | make()، now()، today()، create() |
| محاسبههای تقویمی (استاتیک) | isValid()، isLeapYear()، daysInYear()، daysInMonth() |
| خواندن | getYear()، getMonth()، getDay()، getHour()، getMinute()، getSecond()، getDayOfWeek()، getTimestamp()، getTimezone()، toGregorian() |
| قالببندی | format()، toDateString()، toDateTimeString()، __toString() |
| تغییر | add و sub برای Days، Hours، Minutes، Seconds، Months، Years. و startOf و endOf برای Day، Month، Year |
| مقایسه | eq، ne، gt، gte، lt، lte، equals، isBefore، isAfter، between، isPast، isFuture، isToday |
| اختلاف | diffInDays()، diffInMonths()، diffInYears() |
اینها برای هر سه کلاس برقرار است:
- شیءها
finalو تغییرناپذیرند. متدهایی که تاریخ را عوض میکنند شیء تازه میدهند. - هر متدی که تاریخ یا زمان یونیکس یا مقدار جابهجایی بگیرد، برای ورودی بیرون از بازه فقط
InvalidDateExceptionمیدهد.TypeErrorیاValueErrorبیرون نمیآید. - در قرارداد،
format()فقط الگو میگیرد. هر کلاس پارامترهای اختیاری خودش را آخر آن اضافه میکند ($persianDigitsبرای جلالی،$localeو$digitsبرای هجری،$localeبرای عبری). از راه اینترفیس فقطformat($pattern)را میتوانید صدا بزنید. - شمارهٔ روز هفته یکسان نیست . جلالی از شنبه شروع میکند. هجری و عبری از یکشنبه.
$i = new DateTimeImmutable('2025-10-07', $utc); // سهشنبه
echo Jalali::make($i)->getDayOfWeek(), ' ', Hijri::make($i)->getDayOfWeek(), ' ', Hebrew::make($i)->getDayOfWeek();
// 3 2 2 (جلالی: شنبه = 0. دو تقویم دیگر: یکشنبه = 0)مقایسه بین تقویمها
همهٔ متدهای مقایسه CalendarDate|DateTimeInterface میگیرند و زمان یونیکس را مقایسه میکنند. لازم نیست اول تبدیل کنید:
$nowruz = Jalali::create(1405, 1, 1, 12, 0, 0, $utc);
var_dump($nowruz->eq(Hijri::make($nowruz))); // bool(true)
var_dump($nowruz->eq($nowruz->toGregorian())); // bool(true)
var_dump($nowruz->gt(Hebrew::create(5785, 1, 1, 0, 0, 0, $utc))); // bool(true)
var_dump($nowruz->between(Hijri::create(1447, 8, 1, 0, 0, 0, $utc),
Hebrew::create(5787, 1, 1, 0, 0, 0, $utc))); // bool(true)متد between($a, $b, $equal = true) دو کران را به هر ترتیبی قبول میکند. اگر false ندهید، خود کرانها هم داخل بازهاند. برابری یعنی یک لحظه بودن. Jalali::create(1405, 1, 1) در UTC با همان تاریخ در تهران برابر نیست، چون ۳٫۵ ساعت فاصله دارند.
برای مرتبکردن فهرستی از تقویمهای مختلف، با getTimestamp() مرتب کنید:
$list = [
Hebrew::create(5786, 1, 1, 0, 0, 0, $utc),
Jalali::create(1405, 1, 1, 0, 0, 0, $utc),
Hijri::create(1447, 1, 1, 0, 0, 0, $utc),
];
usort($list, fn (CalendarDate $a, CalendarDate $b) => $a->getTimestamp() <=> $b->getTimestamp());
foreach ($list as $d) { echo $d::class, ' ', $d->toGregorian()->format('Y-m-d'), "\n"; }
// RtlyKit\Calendar\Hijri 2025-06-26
// RtlyKit\Calendar\Hebrew 2025-09-23
// RtlyKit\Calendar\Jalali 2026-03-21اختلاف بین تقویمها
متد diffInDays() روزهای کامل بین دو لحظه را میشمارد و به تقویم کاری ندارد. diffInMonths() و diffInYears() ماه و سال کامل را در تقویمِ همان شیئی که صدا میزنید میشمارند. تاریخ دیگر اول به همان تقویم برده میشود. اگر $absolute = false بدهید، علامت نتیجه علامتِ $this - $other است.
$target = Hijri::create(1447, 9, 1, 0, 0, 0, $utc); // اول رمضان 1447
echo $nowruz->diffInDays($target); // 31
echo $nowruz->diffInDays($target, false); // 31 ($nowruz دیرتر از $target است)
echo $target->diffInDays($nowruz, false); // -31
echo $nowruz->diffInMonths($target); // 1 (ماه جلالی)
echo Hijri::make($nowruz)->diffInMonths($nowruz->addMonths(3)); // 3 (ماه هجری)
echo $nowruz->diffInYears(Hijri::create(1450, 1, 1, 0, 0, 0, $utc)); // 2پس جواب «چند ماه مانده» به تقویمی که میپرسید بستگی دارد. همان تقویمی را بردارید که کاربرانتان با آن فکر میکنند. جدول واحدها برای هر تقویم در جلالی، هجری و عبری هست.
موارد مرزی و محدودیتها
- بازهها. جلالی -۶۲۰ تا ۹۳۷۷، هجری ۱ تا ۹۶۶۵، عبری ۳۷۶۲ تا ۱۳۷۵۹. اگر تقویم مقصد آن لحظه را در بازهٔ خود نداشته باشد،
InvalidDateExceptionمیگیرید. - گونهٔ هجری. وقتی تاریخ هجری را به تقویم دیگر ببرید و برگردانید، لحظه همان میماند. گونه همان است که در
make()مقصد دادهاید (بهطور پیشفرض امالقری). - دقت. جلالی با قاعدهٔ حسابی ۳۳ ساله کار میکند و برای ۱۲۰۶ تا ۱۴۹۷ با تقویم رسمی دانشگاه تهران برابر است. جدول امالقری برای ۱۳۱۸ تا ۱۵۰۰ هجری قمری با تقویم رسمی KACST میخواند (بررسی در 2026-10-08). برای ۱۳۰۰ تا ۱۳۱۷ داده از ICU/CLDR است. بیرون از ۱۳۰۰ تا ۱۵۰۰ قاعدهٔ حسابی Tabular کار میکند. جزئیات در دقت و داده .
- خطاها. برای مشکل تقویمی
InvalidDateExceptionرا بگیرید و برای هر خطای کتابخانهRtlyKit\Exceptions\RtlyKitExceptionرا ( مدیریت خطا ).
این صفحه مفید بود؟