كيفية حساب الأيام بين التواريخ في PHP: 5 أخطاء قاتلة

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

«كم يوماً مضى؟» — سؤال يحير المبتدئين

\n\n

يواجه كل مطور PHP عاجلاً أم آجلاً مهمة: معرفة عدد الأيام بين تاريخين. قد يبدو الأمر بسيطاً؟ نأخذ سلسلتين، نطرح إحداهما من الأخرى — وينتهي الأمر. ولكن هنا تحديداً، من العدم، ترتكب أكثر الأخطاء غدراً.

\n\n

ألقينا نظرة على Stack Overflow ووجدنا سؤالاً حقيقياً «Finding the number of days between two dates» حصد آلاف المشاهدات. اتضح أنه حتى المبرمجين ذوي الخبرة يقعون في فخاخ تتعلق بالمناطق الزمنية، وأختام unix، والسلوك غير المتوقع لـ strtotime().

\n\n

في هذه المقالة، سنستعرض خمسة من أكثر الأخطاء شيوعاً عند حساب عدد الأيام بين التواريخ في PHP ونوضح كيفية تجنبها. جهّز محررك — سيكون هناك الكثير من الأكواد والنصائح العملية.

\n\n

الخطأ رقم 1: طرح أختام unix «بطريقة مباشرة»

\n\n

الخطأ الأكثر شيوعاً — محاولة الحصول على الفرق بين التواريخ بطرح الطوابع الزمنية (timestamps) مباشرة:

\n\n
<?php\n$date1 = strtotime('2024-01-01');\n$date2 = strtotime('2024-01-10');\n$days = ($date2 - $date1) / (60 * 60 * 24);\necho $days; // 9\n?>
\n\n

ظاهرياً، كل شيء يعمل. لكن جرب تحويل الساعات إلى التوقيت الصيفي. عند الانتقال إلى «التوقيت الصيفي»، تقصر الأيام بمقدار ساعة، وعند العودة تطول. النتيجة: 9.04166 أو 8.95833 يوماً بدلاً من 9 بالضبط.

\n\n

كيفية الإصلاح

\n

استخدم كائنات DateTime وطريقة diff(). فهي تراعي جميع القفزات الزمنية:

\n\n
<?php\n$date1 = new DateTime('2024-01-01');\n$date2 = new DateTime('2024-01-10');\n$interval = $date1->diff($date2);\necho $interval->days; // 9 — دائماً صحيح\n?>
\n\n

العمل مع فرق التواريخ PHP عبر DateTime::diff هو المعيار الصناعي. احفظ هذا النمط.

\n\n

الخطأ رقم 2: تجاهل المنطقة الزمنية

\n\n

تخيل: خادمك موجود في أوروبا/موسكو، ومستخدم من نيويورك يدخل تاريخ «2024-03-10». تنشئ DateTime دون تحديد المنطقة الزمنية. يستخدم PHP المنطقة الزمنية للنظام للخادم. النتيجة: قد «ينزلق» الفرق في الأيام بمقدار يوم واحد.

\n\n

هذا مهم بشكل خاص لحدود الأشهر والانتقال إلى التوقيت الصيفي. يظهر الخطأ نادراً، ولكن عندما يظهر في بيئة الإنتاج — يكون من الصعب جداً اكتشافه.

\n\n

الحل: حدد المنطقة الزمنية بوضوح

\n
<?php\n$tz = new DateTimeZone('UTC');\n$date1 = new DateTime('2024-03-10', $tz);\n$date2 = new DateTime('2024-03-20', $tz);\n$interval = $date1->diff($date2);\necho $interval->days; // 10 — بدقة\n?>
\n\n

استخدم دائماً UTC للحسابات الداخلية. إذا كنت بحاجة لعرض التاريخ للمستخدم — قم بتحويله إلى منطقته المحلية فقط في مرحلة الإخراج.

\n\n

الخطأ رقم 3: الخلط بين days و format('%a')

\n\n

كائن DateInterval يحتوي على خاصية days وطريقة format('%a'). يبدو أنهما نفس الشيء. لكن هناك فارق:

\n\n
    \n
  • $interval->days — العدد الإجمالي للأيام (يشمل جميع الأشهر والسنوات). القيمة دائماً صحيحة.
  • \n
  • $interval->format('%a') — نفس الشيء، ولكن كسلسلة نصية.
  • \n
  • $interval->d — الأيام فقط بدون احتساب الأشهر. إذا كان الفرق 35 يوماً، فإن d سيعيد 4 (الباقي بعد طرح شهر).
  • \n
\n\n

غالباً ما يخلط المبتدئون بين d و days. ونتيجة لذلك، يحصلون على 4 أيام بدلاً من 35. ومن هنا تأتي الأخطاء في التقارير، والفواتير، وجداول المهام.

\n\n

تحقق دائماً من الخاصية التي تستخدمها

\n
<?php\n$date1 = new DateTime('2024-01-01');\n$date2 = new DateTime('2024-02-05');\n$interval = $date1->diff($date2);\n\necho $interval->days; // 35\necho $interval->d;    // 4 — ليس نفس الشيء!\n?>
\n\n

إذا كنت تحتاج تحديداً إلى عدد الأيام بين تاريخين — استخدم

المدونات

توصيات الكتب