«كم يوماً مضى؟» — سؤال يحير المبتدئين
\n\nيواجه كل مطور PHP عاجلاً أم آجلاً مهمة: معرفة عدد الأيام بين تاريخين. قد يبدو الأمر بسيطاً؟ نأخذ سلسلتين، نطرح إحداهما من الأخرى — وينتهي الأمر. ولكن هنا تحديداً، من العدم، ترتكب أكثر الأخطاء غدراً.
\n\nألقينا نظرة على Stack Overflow ووجدنا سؤالاً حقيقياً «Finding the number of days between two dates» حصد آلاف المشاهدات. اتضح أنه حتى المبرمجين ذوي الخبرة يقعون في فخاخ تتعلق بالمناطق الزمنية، وأختام unix، والسلوك غير المتوقع لـ strtotime().
في هذه المقالة، سنستعرض خمسة من أكثر الأخطاء شيوعاً عند حساب عدد الأيام بين التواريخ في 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(). فهي تراعي جميع القفزات الزمنية:
<?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 هو المعيار الصناعي. احفظ هذا النمط.
الخطأ رقم 2: تجاهل المنطقة الزمنية
\n\nتخيل: خادمك موجود في أوروبا/موسكو، ومستخدم من نيويورك يدخل تاريخ «2024-03-10». تنشئ DateTime دون تحديد المنطقة الزمنية. يستخدم PHP المنطقة الزمنية للنظام للخادم. النتيجة: قد «ينزلق» الفرق في الأيام بمقدار يوم واحد.
هذا مهم بشكل خاص لحدود الأشهر والانتقال إلى التوقيت الصيفي. يظهر الخطأ نادراً، ولكن عندما يظهر في بيئة الإنتاج — يكون من الصعب جداً اكتشافه.
\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
$interval->days— العدد الإجمالي للأيام (يشمل جميع الأشهر والسنوات). القيمة دائماً صحيحة. \n $interval->format('%a')— نفس الشيء، ولكن كسلسلة نصية. \n $interval->d— الأيام فقط بدون احتساب الأشهر. إذا كان الفرق 35 يوماً، فإنdسيعيد 4 (الباقي بعد طرح شهر). \n
غالباً ما يخلط المبتدئون بين d و days. ونتيجة لذلك، يحصلون على 4 أيام بدلاً من 35. ومن هنا تأتي الأخطاء في التقارير، والفواتير، وجداول المهام.
تحقق دائماً من الخاصية التي تستخدمها
\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إذا كنت تحتاج تحديداً إلى عدد الأيام بين تاريخين — استخدم