دالة الوقت والتاريخ فى 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. مناطقُ الخطر والأخطاء الشائعة
- نسيان ضبط
date.timezone
فيphp.ini
⇢ ينتجُ تنبيه “Timezone not set”. - الاعتماد على أنظمة 32-بت
⇢ ينهارُ التطبيق عام 2038 عندما يتجاوز الطابع الزمني حدَّه الأقصى. - تجاهل DST
⇢ تبلغُ الحساباتُ في ليلة تقديم الساعة أو إرجاعها قيمًا خاطئة. - الخلط بين التوقيت المحليّ و UTC في التخزين
⇢ يُفضَّلُ التخزينُ بالـ UTC والعرضُ حسب منطقة المستخدم. - تمريرُ سلاسل “غامضة” إلى
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. سيناريوهات متقدّمة
- توقيت الصلاة: الحسابُ الفلكيّ، معالجةُ تقويمٍ هجريٍّ متغيّر.
- سيرفر متعدّدُ المناطق: الحفاظُ على ساعات النظام متزامنةً بـ NTP، وضبطُ PHP-FPM على
date.timezone=UTC
. - لقطاتٌ بيانيّة للعملات: استخدامُ طابع زمني ميلي/مايكروثانية (
hrtime()
,microtime(true)
).
13. استكشافُ الأخطاء وإصلاحُها (-Troubleshooting)
- حالة: اختلافُ الموعد المعرَض بساعةٍ واحدة.
التشخيص: المنطقةُ الزمنيّةُ فيphp.ini
لا تطابقُ قاعدة المستخدم.
العلاج:date_default_timezone_set('Asia/Amman');
- حالة: فشلُ معالجة “29-02-2023”.
التشخيص: سنةٌ غيرُ كبيسة.
العلاج: استخدمcheckdate()
قبل التخزين.
14. خاتمةٌ شاملة
يتطلّبُ التعاملُ مع الوقت والتاريخ في PHP مزيجًا من الإلمام النظري بالمنطقة الزمنيّة والطابع الزمني، والتمكّن التطبيقي من الدوالّ الإجرائيّة والفئات الكائنيّة الجديدة، إضافةً إلى أخذ تحدّيات التدويل والتوقيت الصيفي والأداء بعين الاعتبار. بتبنّي ممارساتٍ مثل تخزين UTC، واستخدام DateTimeImmutable
، وتحديث tzdata، وتغطية الحالات الحَرِجة اختباريًّا، يمكن للمطوّر بناءُ أنظمةٍ زمنيّةٍ موثوقةٍ وقابلةٍ للتوسّع. في نهاية المطاف، تُعدّ القدرةُ على تمثيل الوقت بدقّةٍ عنصرًا أساسيًّا في سلامةِ المعاملات، وأمانِ البيانات، وثقةِ المستخدمين، وهي مسؤوليّةٌ لا يمكن التهاون فيها أبدًا.