في هذه الصفحة
- الإعداد والدوال المساعدة
- التقاويم
- رقم يوم الأسبوع يختلف بين الجلالي والهجري
- jdate('1405-01-01') و jdate('2026-03-21') كلاهما يعمل، لكن سنة ميلادية مثل 999 لا تعمل
- format() تطبع أرقامًا إنجليزية. كيف أحصل على أرقام فارسية؟
- jdate('1404/12/30') تُثير استثناءً، لكن 1403/12/30 تعمل
- «اليوم» يختلف بيوم واحد عند مستخدميّ
- يظهر لي InvalidDateException لسنة بعيدة في المستقبل أو رقم ضخم
- التاريخ الهجري يختلف بيوم عن الإعلان المحلي
- Carbon وLaravel
- أدوات التحقق والبيانات
- الأعداد والنصوص
- أوقات الصلاة والعطل
فحصنا كل إجابة أدناه مقابل الشيفرة، وشغّلنا الأمثلة. وإن لم تجد مشكلتك هنا، فانظر أولًا معالجة الأخطاء (معنى كل رمز استثناء) والحدود.
الإعداد والدوال المساعدة#
تظهر لي الرسالة "Call to undefined function jdate()". أين الدوال المساعدة؟#
الدوال المساعدة دوال ضمن فضاء الأسماء RtlyKit. والحزمة لا تعرّف أي دالة عامة افتراضيًا، فلا تتعارض مع شيفرتك ولا مع حزمة أخرى. استورد ما تستخدمه، أو استدعِه بالاسم الكامل، أو فعّل الأسماء العامة القصيرة مرة واحدة عند الإقلاع:
<?php
require __DIR__.'/vendor/autoload.php';
use function RtlyKit\jdate; // option 1: import
echo jdate('2026-03-21')->format('Y/m/d'), "\n"; // 1405/01/01
echo \RtlyKit\jdate('2026-03-21')->format('Y/m/d'), "\n"; // option 2: full name
$skipped = \RtlyKit\Globals::register(); // option 3: short global names
echo \jdate('2026-03-21')->format('Y/m/d'), "\n"; // 1405/01/01
var_dump($skipped); // array(0) {} (nothing was already taken)
لا تستبدل Globals::register() دالة موجودة ولا تُثير استثناءً؛ وتُرجع الأسماء التي تخطّتها لتسجّلها إن أردت. في Blade استدعِ \RtlyKit\jdate(...)، أو سجّل الدوال العامة من AppServiceProvider::register(). فمزوّد الخدمة في Laravel لا يسجّلها عنك. انظر الدوال المساعدة والدوال العامة.
أي استثناء ألتقط؟#
التقط RtlyKit\Exceptions\RtlyKitThrowable (أو RtlyKitException) للمكتبة كلها، أو صنفًا فرعيًا مثل InvalidDateException. أدوات التحقق لا تُثير استثناءً أصلًا، فلا تحتاج إلى try. وقرّر بحسب getErrorCode() لا بحسب نص الرسالة. التفاصيل في معالجة الأخطاء.
التقاويم#
رقم يوم الأسبوع يختلف بين الجلالي والهجري#
هذا مقصود. تعدّ Jalali::getDayOfWeek() (ورمز التنسيق w) من السبت، أول أيام الأسبوع الفارسي: السبت 0 والجمعة 6. أما Hijri وHebrew فتعدّان من الأحد كما تفعل date('w') في PHP، فالسبت 6. هذا اليوم نفسه، 2026-03-21 (سبت):
use function RtlyKit\{jdate, hdate, hebrew_date};
echo jdate('2026-03-21')->getDayOfWeek(), ' ',
hdate('2026-03-21')->getDayOfWeek(), ' ',
hebrew_date('2026-03-21')->getDayOfWeek(), "\n"; // 0 6 6
إذا أردت ترقيمًا موحدًا لكل التقاويم، فاستعمل toGregorian()->format('w').
jdate('1405-01-01') و jdate('2026-03-21') كلاهما يعمل، لكن سنة ميلادية مثل 999 لا تعمل#
النص بالصيغة Y/m/d أو Y-m-d يُقرأ على أنه تاريخ في تقويم الصنف نفسه حين تكون السنة أقل من 1700 (وفي Hebrew حين تكون السنة 3000 أو أكثر)، وعلى أنه ميلادي فيما عدا ذلك. لذلك يُساء فهم تاريخ ميلادي حقيقي بسنة صغيرة. مرّر DateTimeImmutable بدلًا منه، فهو لا يُعاد تفسيره أبدًا:
use function RtlyKit\jdate;
echo jdate('2026-03-21')->format('Y/m/d'), "\n"; // 1405/01/01 (year >= 1700: Gregorian)
echo jdate('1405-01-01')->toGregorian()->format('Y-m-d'), "\n"; // 2026-03-21 (year < 1700: Jalali)
echo jdate('0999-01-01')->format('Y/m/d'), "\n"; // 0999/01/01 (Jalali year 999)
echo jdate(new DateTimeImmutable('0999-01-01'))->format('Y/m/d'), "\n"; // 0377/10/11 (Gregorian year 999)
تُحوَّل الأرقام الفارسية والعربية أولًا، فيعمل '۱۴۰۴/۰۱/۰۱'. والنص الفارغ يُثير InvalidDateException، وnull تعني «الآن».
format() تطبع أرقامًا إنجليزية. كيف أحصل على أرقام فارسية؟#
يُرجع التنسيق أرقامًا لاتينية عمدًا، لتكون النتيجة آمنة لقواعد البيانات والروابط. حوّل الناتج عند عرضه:
use function RtlyKit\{jdate, to_persian};
echo jdate('2026-03-21')->format('Y/m/d'), "\n"; // 1405/01/01
echo to_persian(jdate('2026-03-21')->format('Y/m/d')), "\n"; // ۱۴۰۵/۰۱/۰۱
ويمكن لـ Hijri::format() أن تكتب الأرقام بنفسها عبر وسيطها $digits (latin أو persian أو arabic).
jdate('1404/12/30') تُثير استثناءً، لكن 1403/12/30 تعمل#
لشهر اسفند 30 يومًا في السنة الكبيسة فقط. السنة 1403 كبيسة و1404 ليست كبيسة، فالتاريخ 1404/12/30 غير موجود ويُثير InvalidDateException برمز invalid_date. والشهر 13، أو اليوم 31 في شهر من النصف الثاني من السنة (مثل 1404/07/31)، يتصرف بالطريقة نفسها.
«اليوم» يختلف بيوم واحد عند مستخدميّ#
تستخدم jdate() بلا وسيط المنطقة الزمنية الافتراضية في PHP (date_default_timezone_get()، وغالبًا UTC على الخوادم). وقرب منتصف الليل بتوقيت طهران يكون ذلك اليوم الجلالي السابق أو التالي. مرّر DateTimeZone أو اضبط المنطقة الزمنية الافتراضية في تطبيقك. ووسيط المنطقة الزمنية يحوّل اللحظة الواردة:
use function RtlyKit\jdate;
$utc = new DateTimeImmutable('2026-03-20 22:00', new DateTimeZone('UTC'));
echo jdate($utc)->format('Y/m/d H:i'), "\n"; // 1404/12/29 22:00
echo jdate($utc, new DateTimeZone('Asia/Tehran'))->format('Y/m/d H:i'), "\n"; // 1405/01/01 01:30
يظهر لي InvalidDateException لسنة بعيدة في المستقبل أو رقم ضخم#
لكل تقويم نطاق ثابت (الجلالي من -620 إلى 9377، والهجري من 1 إلى 9665، والعبري من 3762 إلى 13759، والميلادي من 1 إلى 9999)، وتُرفض أيضًا قيم add*() والطوابع الزمنية الضخمة. هذا مقصود: تحصل على استثناء، ولا تحصل أبدًا على تاريخ التفّ حول النطاق. انظر الحدود.
التاريخ الهجري يختلف بيوم عن الإعلان المحلي#
يستخدم Hijri تقويم أم القرى (التقويم المدني السعودي)، وهو محسوب مسبقًا. أما جهات رؤية الهلال المحلية، ومنها في إيران، فقد تبدأ الشهر بعد يوم أو يومين. يغطي الجدول المضمَّن السنوات الهجرية 1300 إلى 1500؛ وخارجه، ومع HijriVariant::Tabular، يكون التاريخ حسابيًا وقد يختلف عن الرؤية بيوم أو يومين. انظر التقويم الهجري والدقة والبيانات.
Carbon وLaravel#
Call to undefined method toJalali() على كائن Carbon#
لا تُسجَّل ماكروات Carbon (toJalali وjformat وcreateFromJalali وtoHijri وtoHebrew وcreateFromHijri وcreateFromHebrew) إلا عند تثبيت nesbot/carbon (الإصدار 3). يسرده Composer اقتراحًا، فثبّته بنفسك: composer require nesbot/carbon. تُسجَّل الماكروات حين يحمّل المحمِّل التلقائي في Composer ملف الدوال المساعدة للحزمة (ومرة أخرى بواسطة مزوّد خدمة Laravel عند الإقلاع)، لكل من Carbon وCarbonImmutable. وIlluminate\Support\Carbon في Laravel يرث Carbon، فيعمل أيضًا:
use Carbon\Carbon;
echo Carbon::parse('2026-03-21')->toJalali()->format('Y/m/d'), "\n"; // 1405/01/01
echo Carbon::createFromJalali(1405, 1, 1)->toDateString(), "\n"; // 2026-03-21
var_dump(Carbon::hasMacro('toJalali')); // bool(true)
إذا كانت hasMacro() تُرجع false، فإما أن Carbon غير مثبّتة وإما أن إصدارها الرئيسي غير مدعوم. انظر ماكروات Carbon.
قواعد التحقق في Laravel (national_code وsheba ...) غير موجودة#
مع الاكتشاف التلقائي للحزم يُسجَّل مزوّد الخدمة عنك. وإن كنت عطّلت الاكتشاف لهذه الحزمة (dont-discover) أو تستخدم إعدادًا قديمًا مخزَّنًا مؤقتًا، فسجّل RtlyKit\Laravel\RtlyKitServiceProvider بنفسك وامسح الذاكرات المؤقتة. أسماء القواعد: national_code وsheba وbank_card وiran_mobile (واسمها البديل mobile) وpostal_code وvehicle_plate. الرسائل بالفارسية والإنجليزية والعربية وتتبع app()->getLocale()، وتبقى أسطر lang/{locale}/validation.php الخاصة بك هي الأعلى أولوية. انظر إعداد Laravel.
نموذج Eloquent عندي يُثير InvalidDateException عند إسناد تاريخ#
يقبل JalaliCast كائن Jalali، وأي DateTimeInterface، وطابعًا زمنيًا بنظام Unix، ونصًا ميلاديًا، أو نصًا جلاليًا مثل 1404/01/15 10:30 (الأرقام الفارسية مقبولة، وكذلك / أو -). وأي شيء آخر خطأ: التاريخ المستحيل والنص العشوائي والقيم غير القياسية (مثل المصفوفة) تُثير InvalidDateException عند الإسناد. أما null والنص الفارغ فيصيران null. التقطه في طلب النموذج (form request) أو في المتحكّم (controller):
$post->published_at = '1404/01/15 10:30'; // stored as 2025-04-04 10:30:00
$post->published_at = '1404/13/45'; // throws InvalidDateException (invalid_date)
$post->published_at = 'hello'; // throws InvalidDateException (invalid_date)
$post->published_at = ['x']; // throws InvalidDateException (invalid_date)
أبقِ العمود من النوع datetime الميلادي العادي: يكتب التحويل Y-m-d H:i:s ويقرؤه مجددًا ككائن Jalali لا يتغير. ولا يجري التحويل (Cast) أي تحويل للمنطقة الزمنية. انظر التحقق والتحويل في Laravel.
أدوات التحقق والبيانات#
is_national_code(13542419) تعطي false، لكن النسخة النصية تعطي true#
فقد int أصفاره البادئة أصلًا: صار 0013542419 هو 13542419، أي ثمانية أرقام. تحوّل أدوات التحقق الأعداد الصحيحة إلى نصوص لكنها لا تستعيد الأصفار. أبقِ المعرّفات نصوصًا في كل مكان (حقول النماذج وJSON وأعمدة قواعد البيانات):
use function RtlyKit\is_national_code;
var_dump(is_national_code(13542419)); // bool(false)
var_dump(is_national_code('0013542419')); // bool(true)
getBankName() تُرجع null لبطاقة أو شبا صالحة#
تحتوي جداول BIN ورموز شبا والمشغّلين على إدخالات أكدها مصدران مستقلان على الأقل فقط، ولذلك هي صغيرة عمدًا (39 رمز BIN و38 رمز شبا). تعني null «غير معروف» لا «غير صالح»؛ فصلاحية البطاقة تأتي من اختبار Luhn وصلاحية شبا من mod-97، بمعزل عن الجداول. والأمر نفسه في NationalCode::getLocation() (547 بادئة)، وهي تعطي مكان إصدار البطاقة لا مكان الولادة. لا ترفض مستخدمًا لأن الاسم null. انظر الدقة والبيانات.
لماذا لا تُثير أداة التحقق استثناءً أبدًا، حتى مع null أو مصفوفة؟#
تأخذ أدوات التحقق mixed وتجيب بـ false أو بـ Result غير صالح: invalid_type للقيم غير القياسية وinput_too_long فوق 4096 بايت. فيمكنك تمرير مدخلات الطلب الخام مباشرة. انظر نظرة عامة على أدوات التحقق.
is_mobile() تعطي true لكن allocated تعطي false#
تفحص is_mobile() شكل الرقم. أما Mobile::isAllocated() ومفتاح التفاصيل allocated فيسألان أيضًا هل تقع البادئة في كتلة تدرجها خطة الترقيم الوطنية للهاتف المحمول. وقد يكون للرقم الصالح allocated = false حين تكون بادئته أحدث من الخطة الموجودة في بياناتنا. وهذا لا يجعل الرقم غير صالح. انظر أرقام الجوال.
الأعداد والنصوص#
format_number() تقصّ العدد العشري إلى 15 رقمًا#
لا يستطيع float في PHP تمثيل معظم الكسور العشرية بدقة. لذلك يكتب المنسِّق العدد العشري بأقصر نص عشري يعيد القراءة إلى القيمة نفسها، وبحد أقصى 15 رقمًا معنويًا. تُطبع 1234567.891 نظيفة، وتعطي 1 / 3 خمسة عشر رقم ثلاثة، و123456789.123456789 كـ float تفقد أرقامها الأخيرة. مرّر الأعداد العشرية نصوصًا حين تحتاج أرقامًا أكثر:
use function RtlyKit\format_number;
echo format_number(1234567.891), "\n"; // ۱٬۲۳۴٬۵۶۷٫۸۹۱
echo format_number(123456789.123456789), "\n"; // ۱۲۳٬۴۵۶٬۷۸۹٫۱۲۳۴۵۷ (float, 15 digits)
echo format_number('123456789.123456789'), "\n"; // ۱۲۳٬۴۵۶٬۷۸۹٫۱۲۳۴۵۶۷۸۹ (string, exact)
number_to_words() تُثير استثناءً مع 1.5 ومع الأعداد الضخمة ومع اللغات الأخرى#
الكلمات معرَّفة للأعداد الصحيحة فقط. 1.5 وNaN وINF تُثير InvalidNumberException، أما float صحيح القيمة مثل 3.0 فيُقبل. الفارسية تصل إلى 21 رقمًا والعربية إلى 27 رقمًا. ولا توجد إلا fa وar؛ وأي لغة أخرى تُثير UnsupportedLocaleException. وللجنس والحالة الإعرابية والحركات في العربية انظر الأعداد بالحروف العربية. الحدود في الحدود.
أوقات الصلاة والعطل#
أوقات الصلاة بمنطقة زمنية خاطئة أو متقدمة بساعة#
الأوقات بصيغة HH:MM بالتوقيت المحلي للمنطقة الزمنية الخاصة بالحاسبة، لليوم التقويمي المحلي للتاريخ الذي تمرّره. تستخدم PrayerTimes::forCity() منطقة المدينة نفسها. أما الحاسبة المبنية بـ new PrayerTimes() دون منطقة فتستخدم الافتراضية في PHP (date_default_timezone_get()، وهي UTC في حاوية جديدة)، فمرّر DateTimeZone. ويُطبَّق التوقيت الصيفي لكل حدث على حدة، فجدول يعبر تغيير الساعة صحيح على جانبيه (الظهر في القاهرة بتاريخي 2026-10-08 و2026-10-31):
use RtlyKit\Prayer\PrayerTimes;
$cairo = PrayerTimes::forCity('cairo', PrayerTimes::METHOD_EGYPT);
echo $cairo->getTimes(new DateTimeImmutable('2026-10-08'))['dhuhr'], ' ', // 12:43 (summer time)
$cairo->getTimes(new DateTimeImmutable('2026-10-31'))['dhuhr'], "\n"; // 11:39 (standard time)
التاريخ الذي تمرّره في منطقة أخرى يُحوَّل أولًا إلى منطقة الحاسبة: 2026-03-20 23:30 UTC و2026-03-21 03:00 Asia/Tehran كلاهما يعطي أوقات 21 مارس في طهران.
بعض أوقات الصلاة قيمتها null#
في أقصى الشمال أو الجنوب، وفي بعض الفصول، لا يوجد شروق ولا غروب أصلًا (النهار أو الليل القطبي). عندئذ تكون sunrise وmaghrib بقيمة null، وتكون asr بقيمة null في الليل القطبي. هذه نتيجة وليست خطأ، فعالجها في واجهتك. أما الفجر والعشاء فتملؤهما قاعدة خطوط العرض العالية الافتراضية. ومع withHighLatitudeRule(HighLatitudeRule::None) قد تكونان null أيضًا:
use RtlyKit\Prayer\PrayerTimes;
$oslo = new PrayerTimes(69.65, 18.96, PrayerTimes::METHOD_MWL, PrayerTimes::ASR_STANDARD, new DateTimeZone('Europe/Oslo'));
echo json_encode($oslo->getTimes(new DateTimeImmutable('2026-06-21'))), "\n";
// {"fajr":"03:10","sunrise":null,"dhuhr":"12:46","asr":"17:58","maghrib":null,"isha":"22:10"}
nextPrayer() أرجعت وقتًا هو الغد#
بعد العشاء تنتقل nextPrayer() إلى فجر الغد. وفي النتيجة مفتاح date (بصيغة Y-m-d) يبيّن في أي يوم تقع الصلاة:
use RtlyKit\Prayer\PrayerTimes;
$next = PrayerTimes::forCity('tehran')->nextPrayer(new DateTimeImmutable('2026-03-21 23:00', new DateTimeZone('Asia/Tehran')));
echo json_encode($next), "\n"; // {"name":"fajr","time":"04:42","date":"2026-03-22"}
أوقاتي تختلف ببضع دقائق عن مسجدي أو عن تطبيق آخر#
تستخدم الجهات المختلفة زوايا شفق وهوامش احتياط وتقريبًا مختلفة. يطابق الحساب الجداول المنشورة التي قارنّاه بها ضمن دقيقة تقريبًا (انظر ما الذي فحصناه). اختر الطريقة التي يتبعها مجتمعك، واضبط معامل العصر (ASR_HANAFI يؤخّر العصر)، وللأماكن المرتفعة استخدم وسيط الارتفاع. وإذا كانت جهتك تضيف بضع دقائق فاستعمل withTune(). انظر أوقات الصلاة.
عطلة دينية تختلف بيوم عن التقويم الرسمي#
في السنوات الجلالية من 1380 إلى 1405 تستعمل المكتبة التواريخ الرسمية المنشورة. وفي السنوات الأخرى تقدّر العطل الإسلامية من التقويم الهجري، بينما تعلنها إيران برؤية الهلال، فقد يختلف التقدير بيوم أو يومين. أما العطل الجلالية الثابتة (مثل النوروز و22 بهمن) فدقيقة. ويمكنك تصحيح السنوات التقديرية بإزاحة أو ببداية شهر حقيقية أو بأيامك أنت: انظر تقويم العطل القابل للتعديل. وتخبرك IranHolidays::sourceOf($year) بمصدر السنة.