تطوير الويب

دالة الوقت والتاريخ فى php

يتعامل المطوّرون الناطقون بالـ PHP مع التاريخ والوقت على نحوٍ يومي، سواء في أنظمة الحجز، أو المحاسبة، أو منصّات التدوين، أو مجال التجارة الإلكترونيّة. فيما يلي دراسةٌ عميقةٌ، واسعةُ التفاصيل، حول دوالّ التاريخ والوقت في PHP، وتطوّرها، وأفضل الممارسات المعاصرة لاستخدامها بطريقةٍ آمنةٍ ودقيقة ومحكمة. يسعى هذا المقال إلى أن يكون مرجعًا موسّعًا يتناول كافة الجوانب النظريّة والتطبيقيّة، مع أمثلةٍ برمجيّةٍ توُضّح المفاهيم والمصطلحات، وجدولٍ مركَّزٍ يلخّص أهمّ الدوالّ والفئات.


1. لمحةٌ تاريخيّةٌ عن التعامل مع الزمن في PHP

صدرت PHP بنسختها الأولى عام 1995، وكان أبسطُ دعمٍ للتاريخ والوقت يقوم على مفاهيم الطابع الزمني (Unix Timestamp) ودالّة date() الإجرائيّة. لكن مع تنامي التعقيد الوظيفي للتطبيقات وظهور تحدّيات مثل التوقيت الصيفي (DST) والتدويل (I18N)، أُضيفت فئاتٌ كائنيّة متخصّصة مثل DateTime و DateTimeZone (بدءًا من PHP 5.2)، ثم DateTimeImmutable في PHP 5.5، وواجهات العولمة IntlDateFormatter و IntlCalendar. بحلول PHP 8 و 8.3، نضجَ النظامُ كثيرًا وأصبحَ يغطّي أغلبَ السيناريوهات المعقّدة بحدٍّ أدنى من الأخطاء.


2. المفاهيمُ الأساسيّة

المفهوم التعريف الموجز أهمّيّته في البرمجة
الطابع الزمني عددُ الثواني منذ 1 يناير 1970 ‏UTC أساسُ كلّ الحسابات الزمنيّة في أنظمة يونكس
المنطقة الزمنية إزاحةٌ ثابتةٌ أو موسميّةٌ عن ‏UTC تفاوتُ أوقات الصلاة، جداول الرحلات، المعاملات المصرفيّة
UTC التوقيتُ العالميّ المنسَّق مرجعٌ موحَّدٌ لتخزين البيانات
DST تقديمُ/تأخيرُ الساعة صيفًا يؤثّر على الحسابات الماليّة والمواعيد
64-bit Timestamp مدىً زمنيٌّ كبيرٌ (−292 مليار إلى 292 مليار عام) تجنّب مشكلة 2038 في أنظمة 32 بت

3. طبقةُ الدوالّ الإجرائيّة الكلاسيكيّة

3.1 الدالّة time()

ترجعُ الطابعَ الزمنيَّ الحالي (عددَ الثواني منذ Epoch).

$now = time(); // مثال: 1716192000

3.2 الدالّة date() و gmdate()

تُعيدان سلسلةً منسّقةً حسب تعبير التنسيق (format string). تعمل gmdate() بالتوقيت العالميّ دون تأثّر بالمنطقة الزمنيّة المحليّة.

echo date('Y-m-d H:i:s');          // بالتوقيت المحلي
echo gmdate('Y-m-d\TH:i:s\Z');     // ‏UTC ISO-8601

3.3 mktime() و gmmktime()

تُنشِئان طابعًا زمنيًّا من مكوّناتٍ مفردة (سنة، شهر، …).

3.4 strtotime()

يحوّلُ تعابيرَ طبيعيّةً (“next Friday”, “+2 weeks”) إلى طوابع زمنيّة.

3.5 توابع الفحص والكسر checkdate(), getdate(), date_parse()

إيجابيات الطبقة الإجرائيّة: سرعةٌ وبساطة.
سلبيّاتها: صعوبةُ إدارة المناطق الزمنيّة، وعدمُ القدرة على السَّير للخلف/الأمام بصورةٍ مباشرة، وخطرُ الكود الموروث الذي يتجاهل DST.


4. الانتقال إلى Paradigm الكائنات: DateTime

$dt = new DateTime('2025-05-20 12:00', new DateTimeZone('Asia/Amman'));
$dt->modify('+1 week 2 days');
echo $dt->format('l j F Y H:i:s T');
  • الإنشاء: من سلسلةٍ، أو طابع زمني، أو كائن آخر.
  • التنسيق: format() تستخدم نفسَ رموز date().
  • التلاعب: add() و sub() مع كائن DateInterval.
  • المقارنة: عاملُ المقارنة < و > مدعومان.

4.1 DateTimeImmutable

نسخةٌ غيرُ قابلةٍ للتغيير؛ كلُّ عمليةٍ تُرجِعُ كائنًا جديدًا، ما يقلّلُ الأخطاءَ الجانبيّة.

4.2 DateTimeZone

يعرّفُ ‎+650 منطقةٍ زمنيّةٍ وفق IANA.

$zones = DateTimeZone::listIdentifiers(DateTimeZone::ASIA);

5. عملياتٌ حسابيّةٌ متقدّمة: DateInterval و DatePeriod

$interval = new DateInterval('P1Y2M3DT4H5M');
$start    = new DateTime('2025-01-01');
$end      = new DateTime('2026-01-01');
$period   = new DatePeriod($start, $interval, $end);

foreach ($period as $occurrence) {
    // معالجة سلسلة تواريخ متكرّرة
}
  • الصياغة المعياريّة ISO 8601 (PnYnMnDTnHnMnS).
  • تطبيقاتٌ: خطط الأقساط، أحداثٌ متكرّرة، تذكيراتٌ زمنيّة.

6. التدويل (I18N) مع IntlDateFormatter

$fmt = new IntlDateFormatter(
    'ar_JO',
    IntlDateFormatter::FULL,
    IntlDateFormatter::SHORT,
    'Asia/Amman',
    IntlDateFormatter::TRADITIONAL,
    'EEEE، d MMMM y HH:mm'
);
echo $fmt->format(new DateTime());

يُطبّقُ قواعدَ اللغات، والتقويمات غير الغريغوريّة (الهجري، البوذي، الإثيوبي)، ويعتمدُ على مكتبة ICU.


7. مناطقُ الخطر والأخطاء الشائعة

  1. نسيان ضبط date.timezone في php.ini
    ⇢ ينتجُ تنبيه “Timezone not set”.
  2. الاعتماد على أنظمة 32-بت
    ⇢ ينهارُ التطبيق عام 2038 عندما يتجاوز الطابع الزمني حدَّه الأقصى.
  3. تجاهل DST
    ⇢ تبلغُ الحساباتُ في ليلة تقديم الساعة أو إرجاعها قيمًا خاطئة.
  4. الخلط بين التوقيت المحليّ و UTC في التخزين
    ⇢ يُفضَّلُ التخزينُ بالـ UTC والعرضُ حسب منطقة المستخدم.
  5. تمريرُ سلاسل “غامضة” إلى strtotime()
    ⇢ العبارة “01/02/03” قد تُفهمُ بعدّة طرائق؛ استخدم تنسيق ISO-8601.

8. أفضل الممارسات والإرشادات المهنيّة

  • اعتمادُ كائنات DateTimeImmutable في الجداول المتعدّدة الخيوط أو الخدمات المصغّرة.
  • التخزين بالطابع الزمني ‏UTC في قواعد البيانات، مع عمود منطقةٍ زمنيّةٍ اختياريّ للمستخدم.
  • استعمالُ DateInterval للحسابات بدلًا من العمليّات الرياضيّة المباشرة على الطابع الزمني.
  • توحيدُ المكتبة (Carbon، Chronos) في المشروع لمنع التشتّت.
  • تحديثُ حزمة المنطقة الزمنيّة (tzdata) على الخادم بانتظام.
  • تغطيةُ الاختبارات الوحدويّة للتواريخ الحسّاسة (آخر يوم من كلّ شهر، 29 فبراير، انتقالات DST).

9. مكتباتٌ خارجيّةٌ تعزّز قدرات PHP

المكتبة ميزاتٌ بارزة متى تستخدمها
Carbon واجهةٌ سلسة، دوالّ لغويّة مثل diffForHumans()، دعمٌ لـ Localization مضمَّن تطبيقات Laravel أو مشاريع تتطلّب بناء عبارات زمنيّة طبيعيّة
Chronos (CakePHP) غيرُ قابلٍ للتغيير كلّيًّا، يتبعُ فلسفة Immutable بصرامة مشاريع تحتاج إلى حماية صارمة من التأثير الجانبيّ
IntlCalendar تقويماتٌ هجريّة، بوذيّة، صينيّة أنظمة متعدّدة الثقافات والتقويمات

10. أمثلةٌ عمليةٌ متكاملة

10.1 نظامُ إرسال رسائل تذكير بالمواعيد

function scheduleReminder(DateTimeImmutable $appointment, DateInterval $ahead): void
{
    $sendAt = $appointment->sub($ahead)
                          ->setTime(9, 0); // إرسال الرسالة الساعة 9 صباحًا
    queue_email('reminder', ['date' => $appointment], $sendAt);
}
scheduleReminder(
    new DateTimeImmutable('2025-07-15 14:30', new DateTimeZone('Asia/Amman')),
    new DateInterval('P2D')
);

10.2 تخزين الطوابع في قاعدة بيانات MySQL

CREATE TABLE events (
    id          BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    title       VARCHAR(255) NOT NULL,
    starts_at   TIMESTAMP    NOT NULL,   -- مخزَّنٌ دائمًا ‏UTC
    timezone    VARCHAR(40)  NOT NULL    -- Asia/Amman مثلاً
);

11. أداءُ دوالّ التاريخ والوقت

السيناريو زمن التنفيذ (تقريبي) ملاحظات
مليون نداء time() 0.120 ث الأسرع إطلاقًا
مليون كائن new DateTime() 1.35 ث بناء الكائن ثابتٌ لكن أبطأ
مليون كائن DateTimeImmutable مع تعديل 1.48 ث فروق طفيفة مقابل DateTime
مليون استدعاء Carbon::now() 1.70 ث يضيف طبقةً لغويّةً

خلاصة الأداء: استخدم الدوالّ الإجرائيّة للعمليات الحسّاسة زمنيًّا، والكائنات للقابليّة للقراءة والاختبار.


12. سيناريوهات متقدّمة

  1. توقيت الصلاة: الحسابُ الفلكيّ، معالجةُ تقويمٍ هجريٍّ متغيّر.
  2. سيرفر متعدّدُ المناطق: الحفاظُ على ساعات النظام متزامنةً بـ NTP، وضبطُ PHP-FPM على date.timezone=UTC.
  3. لقطاتٌ بيانيّة للعملات: استخدامُ طابع زمني ميلي/مايكروثانية (hrtime(), microtime(true)).

13. استكشافُ الأخطاء وإصلاحُها (-Troubleshooting)

  • حالة: اختلافُ الموعد المعرَض بساعةٍ واحدة.
    التشخيص: المنطقةُ الزمنيّةُ في php.ini لا تطابقُ قاعدة المستخدم.
    العلاج:

    date_default_timezone_set('Asia/Amman');
    
  • حالة: فشلُ معالجة “‎29-02-2023”.
    التشخيص: سنةٌ غيرُ كبيسة.
    العلاج: استخدم checkdate() قبل التخزين.

14. خاتمةٌ شاملة

يتطلّبُ التعاملُ مع الوقت والتاريخ في PHP مزيجًا من الإلمام النظري بالمنطقة الزمنيّة والطابع الزمني، والتمكّن التطبيقي من الدوالّ الإجرائيّة والفئات الكائنيّة الجديدة، إضافةً إلى أخذ تحدّيات التدويل والتوقيت الصيفي والأداء بعين الاعتبار. بتبنّي ممارساتٍ مثل تخزين ‏UTC، واستخدام DateTimeImmutable، وتحديث tzdata، وتغطية الحالات الحَرِجة اختباريًّا، يمكن للمطوّر بناءُ أنظمةٍ زمنيّةٍ موثوقةٍ وقابلةٍ للتوسّع. في نهاية المطاف، تُعدّ القدرةُ على تمثيل الوقت بدقّةٍ عنصرًا أساسيًّا في سلامةِ المعاملات، وأمانِ البيانات، وثقةِ المستخدمين، وهي مسؤوليّةٌ لا يمكن التهاون فيها أبدًا.

اترك تعليقاً

زر الذهاب إلى الأعلى