14 الوقت
14.1 مقدمة
الساعات والأيام
تذكر بعض المصادر أن الأولين كانوا يقسمون الوقت على 12 ساعة ليلية (تبدأ بعد غروب الشمس) تتلوها 12 ساعة نهارية (تبدأ بعد شروق الشمس). وهي ساعات متغيرة؛ ففي الصيف تزيد طول ساعة النهار (فوق 60 دقيقة معتدلة) بينما تقصر ساعة الليل (دون 60 دقيقة معتدلة)، ويحصل العكس في الشتاء (فيكون الليل أطول والنهار أقصر). أما عند اعتدال الشمس في أشهر معيَّنة في خط الاستواء فإن ساعات الليل والنهار 60 دقيقة (وهو مقياس الاعتدال). والمرجع في ذلك الساعة الشمسية (المزوَّلة). ولحساب الفترة الزمنية كانوا يستعملون ما يُحرَق كالشمع، أو ثقب في وعاء مدرَّج من ماء أو رمل.
الفصل السابع عشر “في تَعْدِيدِ سَاعَاتِ النَّهارِ واللَّيل على أربع وعشرين لفظة”.
عن حمزة بن الحسن وعليه عهدتها:
سَاعَاتُ النَّهارِ: الشُرُوقُ. ثُمَّ البكورُ. ثُمَّ الغُدْوَةُ. ثُمَّ الضُّحَى. ثُمَّ الهاجِرَةُ. ثُمَّ الظَهِيرَةُ. ثُمَّ الرَّوَاحُ. ثُمَّ العَصْرُ. ثُمَّ القَصْرُ. ثُمَّ الأصِيلُ. ثُمَّ العَشِيُّ. ثُمَّ الغُروبُ. سَاعَاتُ اللَّيلِ: الشَّفَقُ. ثُمَّ الغَسَقُ. ثُمَّ العَتَمَةُ. ثُمَّ السُّدْفَة. ثُمَّ الفَحْمَةُ. ثُمَّ الزُّلَّةُ. ثُمَّ الزُّلْفةُ. ثُمَّ البُهْرَةُ. ثُمَّ السَّحَرُ. ثُمَّ الفَجْرُ. ثُمَّ الصُّبْحُ. ثُمَّ الصَّباحُ
ثم جاءت الساعات الميكانيكية الثابتة التي تعمل وكأن جميع الساعات 60 دقيقة؛ ولا تعتبر شتاءً ولا صيْفًا، ولا نهارًا ولا ليلاً .. لكنها أصبحت هي المتداولة. وقد مرَّ ضبط الساعة بأطوار من الدقة، فبدأت من الساعة المتأرجحة (1657) إلى الكرونومتر (1762) إلى مذبذب الكوارتز (1927) إلى الساعة الذرية (1949) إلى ساعة شعاع السيزيوم (1955) إلى ساعة نافورة السيزيوم (1993) إلى الساعة الضوئية (Optical Clock: 2006) والتي تحيد بمقدار ثانية بعد كل 30 مليار سنة.
التوقيت العالمي والمناطق الزمنية
ظهر نظام التوقيت العالمي المنسق (UTC: Coordinated Universal Time) حوالي سنة 1967، لتسهيل التعامل بين الدول والتواصل عبر القارات. فهو نظام للوقت يعتمد على خطوط الطول الأرضية، تقسَّم فيه الجغرافيا لمناطق زمنية بحسب بعدها عن خط طول جرينيتش الذي كان هو نقطة الصفر (UTC+00:00) أي: المرجِع: فما يكون شرقيها يكون الفارق فيه بالموجب، وما يكون غربيَّها يكون الفارق فيه بالسالب.
وكل منطقة زمنية لها توقيت محلي تعتمده في معاملاتها اليومية فيما يتعلق بالوقت من تواصل وتنسيق ومواعيد ونحو ذلك. في الخريطة أدناه نرى تقسيم المناطق الزمنية:
لاحظ أولاً أن الخطوط ليست طوليَّة بالفعل، انظر إلى الألوان فليست هي مستطيلات بل تتعرَّج بحسب حدود الدُّول في الغالب. فالفعل ليس بالبساطة التي قد نعتقدها: فليس الوقت المحلي هو فقط زيادة أو نقص من الوقت العالمي .. بل هناك عدة اعتبارات للتحويل بينها:
- مناطق عريضة جغرافيًّا: كالصين التي تمتد لتغطي مجموعة خطوط طول إلا أنها تعتمد توقيتًا موحَّدًا.
- التوقيت الصيفي: بعض المناطق الزمنية تقدِّم الوقت ساعة عند الربيع (أو نهاية الشتاء) ثُم تعيدُه في الخريف، وذلك لتنظيم جدوَل الناس بحيث يتعرضوا للشمس أكثر.
- قرارات سياسية: قررت بعض الدوَّل أن تغير منطقتها الزمنية في سنة من السنوات؛ فذلك يجب أن يؤخذ في عين الاعتبار عند حساب الأوقات قبل أو بعد هذه السنة لهذه الدُّوَل.
معلومة جانبية: مصطلح التنسيق في التوقيت العالمي المنسق يشير إلى أنه يضع في الحسبان الاختلاف اليسير بسبب الثواني الكبسية، فتعاد ضبط الأوقات لاعتبارها.
نخلص من ذلك أن التعامل مع الوقت له اعتبارات كثيرة بسبب ظروف تاريخية وسياسية وليس خاضعًا لقوانين فيزيائية أو أرضية أو فلكية بحتة. ولذلك ظهرت قاعدة بيانات للمناطق الزمنية (بمجهود جماعي) تتضمن معلومات الدول بشكل يتم تحديثه بشكل مستمر لمتابعة التغيرات، تسمَّى: (tz database).
14.2 الوقت في الحاسب
يظهر وقت التقويم (Calendar Time) على هذا النحو:
- التاريخ:
2024-11-25
- الساعات:
08:30:25
- المنطقة الزمنية:
GMT+3
(أي: ثلاث ساعات متقدِّمة عن جرينيتش)
لكن تمثيل الزمن في الحاسب هو: عدد صحيح (int
) ويمثِّل عدد الثواني من بزوغ فجر نظام يونكس (Unix Epoch) وهو تاريخ ووقت اعتباطي تمَّ وضعه على أن يكون:
- تاريخ:
1970-01-01
- الساعة:
00:00:00
- المنطقة الزمنية:
UTC
التي هيGMT+0
مثال: لنشير إلى سنة واحدة تمامًا بعد النقطة الصفرية، أي: الساعة 00:00:00 بتاريخ 1 يناير1971 ، فإن السنة الواحدة فيها 31,536,000
ثانية ، وبالتالي يكون هذا الرقم هو الذي يمثل ذلك الوقت.
ولو أردت الترجمة بالعكس، فتقول إن 1,000,000,000
ثانية منذ النقطة الصفرية يوافق 9 سبتمبر 2001 01:46:40 في وقت التقويم على منطقة UTC
.
مشكلة سنة 2038 تحصل في الأنظمة ذات 32-بت؛ إذْ عدد الثواني يصل إلى أقصى مداه عند نقطتين زمنيتين:
- ففي النزول تستطيع أن تصل إلى: 20:45:52 UTC بتاريخ 1901-12-13 (باختيار عدد سالب)
- وكذلك في الصعود؛ لا يمكن أن تتعدى: 03:14:07 UTC بتاريخ 2038-01-19
والحل في ذلك بسيط، وهو نقل البرنامج لنظام 64-بت.
14.3 الوقت في بايثون
ننتقل الآن إلى الوقت والتاريخ في بايثون، حيث يوجد لدينا المفاهيم التالية:
أولاً: datetime.date
وهو تاريخ مثالي يفترض أن التقويم الغريغوري يمتد إلى ما لا نهاية في المستقبل والماضي (رغم أنه في الحقيقة حل مكان التاريخ الجولياني سنة 1582). سمات هذا الكائن: السنة والشهر واليوم.
ثانيًا: datetime.time
هو وقت مثالي يفترض 86,400 ثانية في اليوم (بدون ثوانٍ كبيسة). سمات هذا الكائن: الساعة والدقيقة والثانية والميكروثانية وtzinfo (معلومات المنطقة الزمنية).
ثالثًا: datetime.datetime
وهو التاريخ والوقت معًا؛ فلديه سمات كلا الجزئين.
رابعًا: datetime.timedelta
وهو فترة زمنية. ولكننا سنستبدله بـ dateutil.relativedelta
إذ هي كذلك فترة زمنية إلا أن نطاقها أوسع (تستوعب السنين والأشهر، وتعتبر السنوات الكبيسة في الحسبان).
الوقت الصحيح لا بد له من نسبة إلى منطقة زمنيَّة (كأن تقول الساعة 04:00:00 صباحًا بتوقيت UTC+03)؛ فهذا تسميه بايثون وقت واع (Aware)، وأما الوقت الذي لم تحدد منطقته الزمنية (كما لو قُلت في الساعة 04:00:00 صباحًا) فهذا غير منسوب لمنطقة زمنية وبالتالي فهو ساذج (Naive) على تعبيرهم.
ويرشدنا توثيق المكتبة للتوسع في استعمال قاعدة بيانات المناطق الزمنية، والقدرة على تفسير التواريخ والأوقات بمرونة لاستخدام مكتبة dateutil
المتوفرة في PyPI.
لتثبيت المكتبة نستعمل pip
على النحو التالي:
الآن نستورد المكتبة الأساسية datetime
ومكتبة dateutil
:
نريد الآن معرفة الوقت العالمي والمحلي، وكذلك الوقت في القاهرة، وكذلك الوقت في لندن (هنا قائمة بالأسماء):
print(datetime.now(tz=tz.tzutc()))
print(datetime.now(tz=tz.tzlocal()))
print(datetime.now(tz=tz.gettz('Africa/Cairo')))
print(datetime.now(tz=tz.gettz('Europe/London')))
2024-12-13 18:09:15.844209+00:00
2024-12-13 21:09:15.844276+03:00
2024-12-13 20:09:15.844794+02:00
2024-12-13 18:09:15.845219+00:00
لاحظ أن شكل الوقت كاملاً على النحو التالي:
2024-11-19 11:32:35.355104+03:00
YYYY-MM-DD HH:MM:SS.ssssss+HH:MM
نفكك ذلك:
YYYY-MM-DD
هو التاريخ (يبدأ بالسنة ثم الشهر ثم اليوم)HH:MM:SS.ssssss
هو الوقت (بالساعات والدقائق والثواني والميكروثواني)+HH:MM
هو الفرق بين الوقت المحلي لتلك المنطقة الزمنية والوقت العالمي المنسق (UTC).
التفسير: تحويل النص إلى تاريخ ووقت
وقراءة التواريخ أفضل بكثير في مكتبة dateutil
بدلاً من استعمال المكتبة الأساسية datetime
. وتكثر الحاجة لذلك عند استقبال معلومات من الشبكة أو من ملفات أو من المستخدمين:
هنا نحدد وقتًا افتراضيًّا عند القراءة، بحيث لو لم توجد المعلومة عند القراءة فإنها تستعمل القيم الابتدائية:
datetime.datetime(2003, 9, 25, 10, 36, 28)
ونرى كيف أن المفسر يحاول معرفة المعلومات ولو كانت ناقصة:
- دون السنة
- دون الشهر
- دون الثواني
- دون اليوم
الحسابات الزمنية
حساب الزمن المنقضي
حساب الزمن لموعد
مقارنة الوقت
مقارنة الفترة
now = datetime.now(tz=tz.tzlocal())
exam_date = datetime(2024, 11, 19, hour=15, minute=30, second=0, tzinfo=tz.tzlocal())
if relativedelta(now, exam_date).hours < 1:
print('Hurry up!')
elif relativedelta(now, exam_date).hours < 4:
print(f'Remember you have an exam today at {exam_date:%H:%M}')
else:
print(f'You have plenty of time to prepare for the exam')
You have plenty of time to prepare for the exam
الجمعة القادمة
الجمعة الفائتة
حساب الوقت باعتبار منطقتين زمنيتين
لديك اجتماع في وقت محدد بتوقيت لندن، وتريد معرفة وقت الوصول بالطائرة إن كانت الرحلة تستغرق 4 ساعات والإقلاع من القاهرة في الساعة 01:00:00 صباحًا والوجهة لندن:
departure_tz = tz.gettz('Africa/Cairo')
arrival_tz = tz.gettz('Europe/London')
departure_time = datetime(2024, 11, 19, hour=1, tzinfo=departure_tz)
arrival_time = departure_time + relativedelta(hours=4)
print(f'You leave at {departure_time.astimezone(departure_tz)} in Cairo time')
print(f'You arrive at {arrival_time.astimezone(arrival_tz)} in London time')
print(f'which corresponds to {arrival_time.astimezone(departure_tz)} in Cairo time')
You leave at 2024-11-19 01:00:00+02:00 in Cairo time
You arrive at 2024-11-19 03:00:00+00:00 in London time
which corresponds to 2024-11-19 05:00:00+02:00 in Cairo time
تنسيق التاريخ والوقت
وانظر الجدول لتنسيق مظهر التاريخ والوقت:
print(f'Departure time: {departure_time.astimezone(departure_tz):%d %b, %X %Z} in Cairo time')
print(f'Arrival time: {arrival_time.astimezone(arrival_tz):%d %b, %X %Z} in London time')
print(f'which corresponds to {arrival_time.astimezone(departure_tz):%d %b, %X %Z} in Cairo time')
Departure time: 19 Nov, 01:00:00 EET in Cairo time
Arrival time: 19 Nov, 03:00:00 GMT in London time
which corresponds to 19 Nov, 05:00:00 EET in Cairo time
التكرار
تكرار التواريخ يتم في هذه المكتبة باستعمال rrule
ويحدد على النحو التالي:
يوم ويوم
تكرار أوقات بأخذ يوم وترك يوم، ابتداءً من وقت معين في الساعة العاشرة صباحًا:
[datetime.datetime(2024, 11, 19, 10, 0),
datetime.datetime(2024, 11, 21, 10, 0),
datetime.datetime(2024, 11, 23, 10, 0),
datetime.datetime(2024, 11, 25, 10, 0),
datetime.datetime(2024, 11, 27, 10, 0),
datetime.datetime(2024, 11, 29, 10, 0),
datetime.datetime(2024, 12, 1, 10, 0),
datetime.datetime(2024, 12, 3, 10, 0),
datetime.datetime(2024, 12, 5, 10, 0),
datetime.datetime(2024, 12, 7, 10, 0)]
أسبوعي
شهريًّا إلى وقت محدد
[datetime.datetime(2024, 8, 1, 0, 0),
datetime.datetime(2024, 9, 1, 0, 0),
datetime.datetime(2024, 10, 1, 0, 0),
datetime.datetime(2024, 11, 1, 0, 0),
datetime.datetime(2024, 12, 1, 0, 0),
datetime.datetime(2025, 1, 1, 0, 0),
datetime.datetime(2025, 2, 1, 0, 0),
datetime.datetime(2025, 3, 1, 0, 0),
datetime.datetime(2025, 4, 1, 0, 0)]
كل 15 دقيقة لمدة 6 مرات
[datetime.datetime(2024, 11, 19, 10, 0),
datetime.datetime(2024, 11, 19, 10, 15),
datetime.datetime(2024, 11, 19, 10, 30),
datetime.datetime(2024, 11, 19, 10, 45),
datetime.datetime(2024, 11, 19, 11, 0),
datetime.datetime(2024, 11, 19, 11, 15)]
وندعوك للاطلاع على المزيد من الأمثلة على مكتبة dateutil
.
14.4 التاريخ الهجري في بايثون
توفر مكتبة hijridate
التعامل مع التاريخ الهجري والتحويل بينه وبين الجريجوري (الميلادي):