from datetime import date, time, datetime, timedelta
from dateutil import tz
9 الوقت
قال الثعالبي (350 هـ - 429 هـ):
الفصل السابع عشر “في تَعْدِيدِ سَاعَاتِ النَّهارِ واللَّيل على أربع وعشرين لفظة”.
عن حمزة بن الحسن وعليه عهدتها:
سَاعَاتُ النَّهارِ: الشُرُوقُ. ثُمَّ البكورُ. ثُمَّ الغُدْوَةُ. ثُمَّ الضُّحَى. ثُمَّ الهاجِرَةُ. ثُمَّ الظَهِيرَةُ. ثُمَّ الرَّوَاحُ. ثُمَّ العَصْرُ. ثُمَّ القَصْرُ. ثُمَّ الأصِيلُ. ثُمَّ العَشِيُّ. ثُمَّ الغُروبُ.
سَاعَاتُ اللَّيلِ: الشَّفَقُ. ثُمَّ الغَسَقُ. ثُمَّ العَتَمَةُ. ثُمَّ السُّدْفَة. ثُمَّ الفَحْمَةُ. ثُمَّ الزُّلَّةُ. ثُمَّ الزُّلْفةُ. ثُمَّ البُهْرَةُ. ثُمَّ السَّحَرُ. ثُمَّ الفَجْرُ. ثُمَّ الصُّبْحُ. ثُمَّ الصَّباحُ
فكانوا يقسمون الوقت على ثنتي عشرة ساعة من وقت غروب الشمس تتلوها ثنتا عشرة ساعة من وقت طلوعها. فهي ساعات متغيرة؛ حيث تبلغ ساعة النهار في الصيف فوق ستين دقيقة معتدلة، وتقصر ساعة الليل. ويحصل العكس في الشتاء: حيث تبلغ ساعة الليل فوق الستين وتقصر ساعة النهار. أما عند اعتدال الشمس في أشهر معيَّنة في خط الاستواء فإن ساعات الليل والنهار متساوية. وهي ما تُقاسُ عليه الزيادة والنقص؛ فتسمى تلك الساعة ذات الستين دقيقة الساعة المعتدلة.
وكان مما يُعرَف به الوقت: المِزْوَلَة (الجمع: مِزْوَلَات، مَزَاوِل) هي ساعة شمسية وأداة توقيت نهاري، تتكون من عدة نقاط وخطوط، رسمت على صفيحة عريضة، وفي وسطها عصا مستقيمة أفقية يتحدد الوقت من طول ظلها الناتج عن وقوع أشعة الشمس عليها، حيث تترك ظلا متحركا على النقاط والخطوط، وهي من أقدم آلات قياس الوقت.
ولحساب فترة زمنية (مؤقِّت) كانوا يقيسون بمقدار الشموع، فيقاس الوقت بالشمعة والاثنين والثلاثة. وكذلك يُقاس بمدة تسرب الماء أو الرمل من وعاءٍ فيه ثقب صغير أو مجرى ضيِّق.
ثم جاءت الساعات الميكانيكية الثابتة التي تعمل على اعتبار أن جميع الساعات 60 دقيقة. فهذه الساعة تعمل بوتيرة ثابتة لا تتغير شتاءً ولا صيْفًا، ولا نهارًا ولا ليلاً .. وظلت هي المتداولة في عصرنا اليوم.
وقد مرَّ ضبط الساعة بأطوار من الدقة، فبدأت من الساعة المتأرجحة (1657) إلى الكرونومتر (1762) إلى مذبذب الكوارتز (1927) إلى الساعة الذرية (1949) إلى ساعة شعاع السيزيوم (1955) إلى ساعة نافورة السيزيوم (1993) إلى الساعة الضوئية (Optical Clock: 2006).
الوقت في الحاسب
يظهر وقت التقويم (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-بت.
التوقيت العالمي والمناطق الزمنية
ظهر نظام التوقيت العالمي المنسق (UTC: Coordinated Universal Time) في عام 1967، لتسهيل التعامل بين الدول والتواصل عبر القارات. فهو نظام للوقت يعتمد على خطوط الطول الأرضية، تقسَّم فيه الجغرافيا لمناطق زمنية بحسب بعدها عن خط طول جرينيتش الذي يعتبر نقطة الصفر (UTC+00:00) أي: المرجِع: فما يكون شرقيَّها يكون الفارق فيه بالموجب، وما يكون غربيَّها يكون الفارق فيه بالسالب.
والمقصود بالتنسيق (في التوقيت العالمي) اعتبار الاختلاف اليسير بسبب الثواني الكبسية، فتعاد ضبط الأوقات لاعتبارها.
وكل منطقة لها توقيت محلي تعتمده في معاملاتها اليومية فيما يتعلق بالوقت من تواصل وتنسيق ومواعيد ونحو ذلك. وفي الخريطة التالية نرى تقسيم المناطق الزمنية (Timezones) التي تنتمي إليها المناطق الجغرافية:
لاحظ أولاً أن الخطوط ليست طوليَّة كما قد يسبق إلى الظن. فإذا تأملت الألوان رأيتها ليست مستقيمة ومستطيلة بل تتعرَّج بحسب حدود الدُّول في الغالب. ليس الوقت المحلي هو فقط زيادة أو نقص من الوقت العالمي .. بل هناك عدة اعتبارات للتحويل بينها:
- مناطق عريضة جغرافيًّا: كالصين التي تمتد لتغطي مجموعة خطوط طول إلا أنها تعتمد توقيتًا موحَّدًا.
- التوقيت الصيفي: بعض المناطق الزمنية تقدِّم الوقت ساعة عند الربيع (أو نهاية الشتاء) ثُم تعيدُه في الخريف، وذلك لتنظيم جدوَل الناس بحيث يتعرضوا للشمس أكثر.
- قرارات سياسية: قررت بعض الدوَّل أن تغير زمن منطقتها في سنة من السنوات؛ فذلك يجب أن يؤخذ في عين الاعتبار عند حساب الأوقات قبل أو بعد هذه السنة لهذه الدُّوَل.
نخلص من ذلك أن التعامل مع الوقت له اعتبارات كثيرة بسبب ظروف تاريخية وسياسية وليس خاضعًا لقوانين جغرافية أو فيزيائية علمية بحتة. ولذلك ظهرت قاعدة بيانات للمناطق الزمنية (بمجهود جماعي) تتضمن معلومات الدول بشكل يتم تحديثه بشكل مستمر لمتابعة هذه التغيرات، تسمَّى: (tz database).
الوقت في بايثون
تستعمل بايثون مجموعة كائنات للتعامل مع الوقت والتاريخ من حيث إجراء العلاقات والحسابات عليها.
أولاً: 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.
لتثبيت المكتبة نستعمل uv
على النحو التالي:
uv add python-dateutil
الآن نستورد المكتبة الأساسية 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')))
2025-06-08 13:41:40.595569+00:00
2025-06-08 16:41:40.595682+03:00
2025-06-08 16:41:40.601795+03:00
2025-06-08 14:41:40.602445+01: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
. وتكثر الحاجة لذلك عند استقبال معلومات من الشبكة أو من ملفات أو من المستخدمين:
from dateutil.parser import parse
هنا نحدد وقتًا افتراضيًّا عند القراءة، بحيث لو لم توجد المعلومة عند القراءة فإنها تستعمل القيم الابتدائية:
= datetime(2003, 9, 25)
DEFAULT "Thu Sep 25 10:36:28", default=DEFAULT) parse(
datetime.datetime(2003, 9, 25, 10, 36, 28)
ونرى في المثال التالي كيف أن المفسر يحاول معرفة المعلومات ولو كانت ناقصة:
- دون السنة
- دون الشهر
- دون الثواني
- دون اليوم
print(parse("Thu Sep 10:36:28", default=DEFAULT))
print(parse("Thu 10:36:28", default=DEFAULT))
print(parse("Thu 10:36", default=DEFAULT))
print(parse("10:36", default=DEFAULT))
2003-09-25 10:36:28
2003-09-25 10:36:28
2003-09-25 10:36:00
2003-09-25 10:36:00
الحسابات الزمنية
from dateutil.relativedelta import relativedelta
حساب الزمن المنقضي
= datetime.now(tz=tz.tzlocal())
today = datetime(1970, 1, 1, tzinfo=tz.tzlocal())
birthday = relativedelta(today, birthday)
age print(f'You are {age.years} years and {age.months} months old')
You are 55 years and 5 months old
حساب الزمن لموعد
= datetime.now(tz=tz.tzlocal())
today = datetime(2045, 1, 15, tzinfo=tz.tzlocal())
exam_date = relativedelta(exam_date, today)
diff print(f'There are {diff.days} days and {diff.hours} hours remaining')
There are 6 days and 7 hours remaining
مقارنة الوقت
= datetime.now(tz=tz.tzlocal())
now = datetime(2044, 11, 19, hour=9, minute=30, second=0, tzinfo=tz.tzlocal())
exam_date
if now > exam_date:
print('The exam has passed')
elif now < exam_date:
print('The exam is coming')
The exam is coming
مقارنة الفترة
= datetime.now(tz=tz.tzlocal())
now = datetime(2044, 11, 19, hour=15, minute=30, second=0, tzinfo=tz.tzlocal())
exam_date
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')
Hurry up!
الجمعة القادمة
نستطيع استعمال الأسماء الدالة على أيام الأسبوع:
SU
: Sunday (الأحد)MO
: Monday (الاثنين)TU
: Tuesday (الثلاثاء)WE
: Wednesday (الأربعاء)TH
: Thursday (الخميس)FR
: Friday (الجمعة)SA
: Saturday (السبت)
from dateutil.rrule import MO, TU, WE, TH, FR, SA, SU
ثم نستعملها في إجراءات المكتبة:
= datetime.now(tz=tz.tzlocal())
today = today + relativedelta(days=+1, weekday=FR)
next_friday print(f'The next Friday is {next_friday:%Y-%m-%d}')
The next Friday is 2025-06-13
الجمعة الفائتة
= today - relativedelta(days=+1, weekday=FR(-1))
last_friday print(f'The last Friday is {last_friday:%Y-%m-%d}')
The last Friday is 2025-06-06
حساب الوقت باعتبار منطقتين زمنيتين
لديك اجتماع في وقت محدد بتوقيت لندن، وتريد معرفة وقت الوصول بالطائرة إن كانت الرحلة تستغرق 4 ساعات والإقلاع من القاهرة في الساعة 01:00:00 صباحًا والوجهة لندن:
= tz.gettz('Africa/Cairo')
departure_tz = tz.gettz('Europe/London')
arrival_tz
= datetime(2044, 11, 19, hour=1, tzinfo=departure_tz)
departure_time
= departure_time + relativedelta(hours=4)
arrival_time
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 2044-11-19 01:00:00+02:00 in Cairo time
You arrive at 2044-11-19 03:00:00+00:00 in London time
which corresponds to 2044-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
ويحدد على النحو التالي:
from dateutil.rrule import rrule
from dateutil.rrule import DAILY, WEEKLY, MONTHLY, YEARLY, HOURLY, MINUTELY, SECONDLY
from dateutil.rrule import MO, TU, WE, TH, FR, SA, SU
يوم ويوم
تكرار أوقات بأخذ يوم وترك يوم، ابتداءً من وقت معين في الساعة العاشرة صباحًا:
list(
=2, count=10, dtstart=datetime(2044, 11, 19, hour=10))
rrule(DAILY, interval )
[datetime.datetime(2044, 11, 19, 10, 0),
datetime.datetime(2044, 11, 21, 10, 0),
datetime.datetime(2044, 11, 23, 10, 0),
datetime.datetime(2044, 11, 25, 10, 0),
datetime.datetime(2044, 11, 27, 10, 0),
datetime.datetime(2044, 11, 29, 10, 0),
datetime.datetime(2044, 12, 1, 10, 0),
datetime.datetime(2044, 12, 3, 10, 0),
datetime.datetime(2044, 12, 5, 10, 0),
datetime.datetime(2044, 12, 7, 10, 0)]
أسبوعي
list(
=1, count=4, dtstart=datetime(2044, 11, 19, hour=10))
rrule(WEEKLY, interval )
[datetime.datetime(2044, 11, 19, 10, 0),
datetime.datetime(2044, 11, 26, 10, 0),
datetime.datetime(2044, 12, 3, 10, 0),
datetime.datetime(2044, 12, 10, 10, 0)]
شهريًّا إلى وقت محدد
list(
=1,
rrule(MONTHLY, interval=datetime(2044, 8, 1),
dtstart=datetime(2045, 4, 1),
until
) )
[datetime.datetime(2044, 8, 1, 0, 0),
datetime.datetime(2044, 9, 1, 0, 0),
datetime.datetime(2044, 10, 1, 0, 0),
datetime.datetime(2044, 11, 1, 0, 0),
datetime.datetime(2044, 12, 1, 0, 0),
datetime.datetime(2045, 1, 1, 0, 0),
datetime.datetime(2045, 2, 1, 0, 0),
datetime.datetime(2045, 3, 1, 0, 0),
datetime.datetime(2045, 4, 1, 0, 0)]
كل 15 دقيقة لمدة 6 مرات
list(
=15, count=6, dtstart=datetime(2044, 11, 19, hour=10))
rrule(MINUTELY, interval )
[datetime.datetime(2044, 11, 19, 10, 0),
datetime.datetime(2044, 11, 19, 10, 15),
datetime.datetime(2044, 11, 19, 10, 30),
datetime.datetime(2044, 11, 19, 10, 45),
datetime.datetime(2044, 11, 19, 11, 0),
datetime.datetime(2044, 11, 19, 11, 15)]
وندعوك للاطلاع على المزيد من الأمثلة على مكتبة dateutil
.
معرفة نصف الليل وأثلاثه
الليل يبدأ من غروب الشمس وينتهي بطلوع الفجر.
فإذا كانت الشمس تغرب -مثلاً- في الثامنة مساءً والفجر يطلع في الخامسة صباحاً، فإن نصف الليل يكون عند الساعة الثانية عشر والنصف.
وطريقة معرفة الثلث الأخير من الليل سهلة، وهي أن تقسم ساعات الليل من غروب الشمس إلى طلوع الفجر على ثلاثة، فآخر قسم هو ثلث الليل الأخير.
from datetime import datetime
def get_night_times(sunset: datetime, sunrise: datetime):
"""Calculate midnight and start of last third of night."""
= sunrise - sunset
night_duration = sunset + (night_duration / 2)
midnight = sunset + (night_duration / 3)
first_third_end = sunrise - (night_duration / 3)
last_third_start
print(night_duration.total_seconds() / 3600, "طول الليل")
print((86400 - night_duration.total_seconds()) / 3600, "طول النهار")
print(sunset.strftime('%I:%M %p'), "غروب الشمس")
print(first_third_end.strftime('%I:%M %p'), "نهاية ثلث الليل الأول")
print(midnight.strftime('%I:%M %p'), "منتصف الليل")
print(last_third_start.strftime('%I:%M %p'), "بداية ثلث الليل الأخير")
print(sunrise.strftime('%I:%M %p'), "طلوع الفجر")
get_night_times(=datetime(2044, 1, 1, 20, 0), # 8:00 PM
sunset=datetime(2044, 1, 2, 5, 0) # 5:00 AM
sunrise )
9.0 طول الليل
15.0 طول النهار
08:00 PM غروب الشمس
11:00 PM نهاية ثلث الليل الأول
12:30 AM منتصف الليل
02:00 AM بداية ثلث الليل الأخير
05:00 AM طلوع الفجر
التاريخ الهجري في بايثون
وأما التاريخ الهجري، فقد تجد له مكتبات خاصة في قاعدة بيانات الحزم البايثونية PyPI.