اذهب إلى المحتوى

استخراج الوقت باستخدام الوحدتين time و datetime في لغة بايثون


Ola Abbas

قد تشغّل برامجك أثناء جلوسك أمام الحاسوب، ولكنك ستفضّل تشغيلها دون إشرافك المباشر، إذ يمكن لساعة حاسوبك جدولة البرامج لتشغيل الشيفرة البرمجية في وقت وتاريخ محدَّد أو على فترات زمنية منتظمة، فمثلًا يمكن أن يستخلص Scrape برنامجك البيانات من موقع ويب كل ساعة للتحقق من التغييرات أو يجري مهمةً تستخدم وحدة المعالجة المركزية بصورة كبيرة في الساعة 4 صباحًا أثناء نومك، حيث توفر وحدتا time و datetime في لغة بايثون الدوال التي تقدّم هذه الوظائف.

الوحدة time

تُضبَط ساعة نظام حاسوبك على تاريخٍ ووقت ومنطقة زمنية محددة، حيث تسمح الوحدة time المُدمَجة لبرامج بايثون الخاصة بك بقراءة ساعة النظام للوقت الحالي، وتُعَد الدالتان time.time()‎ و time.sleep()‎ الأكثر فائدة في هذه الوحدة.

الدالة time.time()‎

توقيت يونيكس Unix Epoch هو مرجع زمني شائع الاستخدام في البرمجة، وهو الساعة 12 صباحًا في 1 من الشهر الأول من عام 1970 بالتوقيت العالمي المنسق Coordinated Universal Time -أو UTC اختصارًا، حيث تعيد الدالة time.time()‎ عدد الثواني منذ تلك اللحظة التي تمثّل توقيت يونيكس بوصفها قيمةً عشرية Float، والتي تُعَد مجرد عددٍ مع فاصلة عشرية، ويسمى هذا العدد الذي تعيده الدالة time.time()‎ بعلامة يونيكس الزمنية Epoch Timestamp. أدخِل ما يلي مثلًا في الصدفة التفاعلية Interactive Shell:

>>> import time
>>> time.time()
1543813875.3518236

استدعينا الدالة time.time()‎ في 2 من الشهر 12 من عام 2018 في الساعة 9:11 مساءً بتوقيت المحيط الهادئ، وتكون القيمة المُعادة هي عدد الثواني التي مرّت بين توقيت يونيكس ولحظة استدعاء الدالة time.time()‎.

يمكن استخدام علامات يونيكس الزمنية لفحص أداء Profile الشيفرة البرمجية، أي قياس المدة التي يستغرقها تشغيل جزء من هذه الشيفرة البرمجية. إذا استدعيتَ الدالة time.time()‎ في بداية مقطع الشيفرة البرمجية الذي تريد قياس المدة التي يستغرقها تشغيله وفي نهايته مرةً أخرى، فيمكنك طرح العلامة الزمنية الأولى من الثانية لإيجاد الوقت المنقضي بين هذين الاستدعاءين. افتح تبويبًا جديدًا في محرّرك لإنشاء ملفٍ جديد وأدخِل البرنامج التالي مثلًا:

    import time
 def calcProd():
       # حساب حاصل ضرب أول 100,000 عدد
       product = 1
       for i in range(1, 100000):
           product = product * i
       return product

 startTime = time.time()
   prod = calcProd()
 endTime = time.time()
 print('The result is %s digits long.' % (len(str(prod))))
 print('Took %s seconds to calculate.' % (endTime - startTime))

نعرّف الدالة calcProd()‎ ➊ للتكرار ضمن حلقة على الأعداد الصحيحة من 1 إلى 99,999 وإعادة ناتج ضربها. نستدعي الدالة time.time()‎ ونخزّنها في المتغير startTime ➋، ثم نستدعي الدالة time.time()‎ مرةً أخرى بعد استدعاء الدالة calcProd()‎ مباشرةً ونخزّنها في المتغير endTime ➌، ثم نطبع عدد أرقام حاصل الضرب الذي تعيده الدالة calcProd()‎ ➍ والمدة التي استغرقها تشغيل هذه الدالة ➎.

احفظ البرنامج السابق بالاسم calcProd.py وشغّله، حيث سيبدو خرجه كما يلي:

The result is 456569 digits long.
Took 2.844162940979004 seconds to calculate.

ملاحظة: هناك طريقة أخرى لفحص أداء شيفرتك البرمجية باستخدام الدالة cProfile.run()‎ التي توفّر مستوًى أعلى من التفاصيل بدلًا من استخدام تقنية الدالة time.time()‎ البسيطة. اطلّع على مقال قياس أداء وسرعة تنفيذ شيفرة بايثون لمزيدٍ من التفاصيل عن الدالة cProfile.run()‎.

تُعَد القيمة المُعادة من الدالة time.time()‎ مفيدةً للحصول على عدد الثواني منذ توقيت يونيكس إلى لحظة استدعائها بوصفها قيمةً عشرية، ولكن لا يستطيع البشر قراءتها، لذا توجد دالة أخرى هي الدالة time.ctime()‎ التي تعيد سلسلةً نصية تمثّل وصفًا للوقت الحالي. يمكنك أيضًا اختياريًا تمرير عدد الثواني منذ توقيت يونيكس الذي تعيده الدالة time.time()‎ إلى الدالة time.ctime()‎ للحصول على قيمة السلسلة النصية التي تمثّل ذلك الوقت. لندخِل الآن ما يلي في الصدفة التفاعلية:

>>> import time
>>> time.ctime()
'Mon Jun 15 14:00:38 2023'
>>> thisMoment = time.time()
>>> time.ctime(thisMoment)
'Mon Jun 15 14:00:45 2023'

الدالة time.sleep()‎

إذا أردتَ إيقاف برنامجك مؤقتًا لفترة من الوقت، فاستدعِ الدالة time.sleep()‎ ومرّر إليها عدد الثواني التي تريد أن يبقى فيها برنامجك متوقفًا مؤقتًا. إذًا لندخِل ما يلي في الصدفة التفاعلية:

   >>> import time
   >>> for i in range(3):
         print('Tick')
         time.sleep(1)
         print('Tock')
         time.sleep(1)

   Tick
   Tock
   Tick
   Tock
   Tick
   Tock
 >>> time.sleep(5)

تطبع حلقة for الكلمة Tick ➊، وتتوقف مؤقتًا لمدة ثانية واحدة ➋، ثم تطبع الكلمة Tock ➌، وتتوقف مؤقتًا لمدة ثانية واحدة ➍، ثم تطبع الكلمة Tick، وتتوقف مؤقتًا، وهكذا حتى طباعة كلٍّ من الكلمتين Tick و Tock ثلاث مرات.

تُعَد الدالة time.sleep()‎ مُعطِّلة، أي أنها لن تعيد شيئًا ولن تحرّر برنامجك لتنفيذ شيفرة برمجية أخرى إلّا بعد انقضاء عدد الثواني التي مررتها إلى الدالة time.sleep()‎، فمثلًا إذا أدخلتَ time.sleep(5)‎ ➎، فلن تظهر تعليمة المطالبة التالية (‎>>>‎) إلّا بعد مرور 5 ثوانٍ.

تقريب الأعداد

سترى في أغلب الأحيان عند التعامل مع الأوقات قيمًا عشرية تحتوي على العديد من الأعداد بعد الفاصلة العشرية، حيث يمكن تسهيل التعامل مع هذه القيم من خلال تقصيرها باستخدام الدالة ‎round()‎ المُدمَجة مع لغة بايثون، والتي تقرّب الأعداد العشرية إلى الدقة التي تحدّدها، حيث تدخِل العدد الذي تريد تقريبه، بالإضافة إلى وسيط ثانٍ اختياري يمثّل عدد الأعداد بعد الفاصلة العشرية التي تريد تقريبه إليها. إذا حذفتَ الوسيط الثاني، فستقرّب الدالة ‎round()‎ العدد إلى أقرب عدد صحيح كامل بدون فاصلة عشرية. لندخِل مثلًا ما يلي في الصدفة التفاعلية:

>>> import time
>>> now = time.time()
>>> now
1543814036.6147408
>>> round(now, 2)
1543814036.61
>>> round(now, 4)
1543814036.6147
>>> round(now)
1543814037

استوردنا الوحدة time وخزّنا الدالة time.time()‎ في المتغير now، ثم استدعينا الدالة round(now, 2)‎ لتقريب now إلى عددين بعد الفاصلة العشرية، واستدعينا الدالة round(now, 4)‎ للتقريب إلى أربعة أعداد بعد الفاصلة العشرية، واستدعينا الدالة round(now)‎ للتقريب إلى أقرب عدد صحيح.

تطبيق عملي: برنامج المؤقت الزمني الفائق Super Stopwatch

لنفترض أنك تريد تعقّب مقدار الوقت الذي تقضيه لإنجاز المهام المملة التي لم تؤتمتها بعد، فليس لديك مؤقت زمني فعلي ومن الصعب العثور على تطبيق مؤقت زمني مجاني لحاسوبك المحمول أو هاتفك الذكي غير مملوءٍ الإعلانات ولا يرسل نسخة من سجل متصفحك إلى المسوّقين، فمذكور أن هذا التطبيق يمكنه ذلك في اتفاقية ترخيصه التي وافقت عليها ولم تقرأها على الأغلب. إذًا لنكتب برنامج مؤقت زمني بسيط باستخدام لغة بايثون.

إليك الخطوات العامة التي سيطبقها برنامجك:

  1. تعقّب مقدار الوقت المنقضي بين الضغطات على مفتاح ENTER، حيث تبدأ كل ضغطة "دورةً Lap" جديدة في المؤقت.
  2. طباعة رقم الدورة والوقت الإجمالي ووقت الدورة.

يجب أن تطبق شيفرتك البرمجية الخطوات التالية:

  1. إيجاد الوقت الحالي من خلال استدعاء الدالة time.time()‎ وتخزينه بوصفه علامة زمنية في بداية البرنامج، وفي بداية كل دورة أيضًا.
  2. الاحتفاظ بعدّاد دورات وزيادته في كل مرة يضغط فيها المستخدم على مفتاح ENTER.
  3. حساب الوقت المنقضي من خلال طرح العلامات الزمنية.
  4. معالجة الاستثناء KeyboardInterrupt حتى يتمكّن المستخدم من الضغط على الاختصار CTRL-C للإنهاء.

افتح تبويبًا جديدًا في محرّرك لإنشاء ملف جديد واحفظه بالاسم stopwatch.py.

الخطوة الأولى: إعداد البرنامج لتعقّب الأوقات

يحتاج برنامج المؤقت الزمني إلى استخدام الوقت الحالي، لذا يجب استيراد الوحدة time، ويجب أن يطبع برنامجك أيضًا بعض التعليمات المختصَرة للمستخدم قبل استدعاء الدالة input()‎، إذ يمكن أن يبدأ المؤقت بعد أن يضغط المستخدم على مفتاح ENTER، ثم ستبدأ الشيفرة البرمجية في تعقّب أوقات الدورات.

أدخِل الآن الشيفرة البرمجية التالية في محرّر ملفاتك، واكتب تعليقاتٍ في النهاية، والتي تمثّل عناصر بديلة لما تبقى من شيفرتك البرمجية:

#! python3
# stopwatch.py - برنامج مؤقت زمني بسيط

import time

# عرض تعليمات البرنامج
print('Press ENTER to begin. Afterward, press ENTER to "click" the stopwatch.
Press Ctrl-C to quit.')
input()                    # الضغط على مفتاح‫ Enter للبدء
print('Started.')
startTime = time.time()    # الحصول على وقت بدء الدورة الأولى
lastTime = startTime
lapNum = 1

# البدء بتعقّب أوقات الدورات

كتبنا الشيفرة البرمجية لعرض التعليمات للمستخدم وبدء الدورة الأولى وتسجيل الوقت وضبط عدد الدورات على القيمة 1.

الخطوة الثانية: تعقّب أوقات الدورات وطباعتها

لنكتب الآن الشيفرة البرمجية لبدء دورات جديدة، وحساب المدة التي استغرقتها الدورة السابقة، وحساب إجمالي الوقت المنقضي منذ بدء المؤقت الزمني، حيث سنعرض وقت الدورة والوقت الإجمالي ونزيد عدد الدورات بمقدار 1 عند كل دورة جديدة. إذًا أضِف الشيفرة البرمجية التالية إلى برنامجك:

   #! python3
   # stopwatch.py - برنامج مؤقت زمني بسيط

   import time

   --snip--
   # البدء بتعقّب أوقات الدورات
 try:
     while True:
        input()
         lapTime = round(time.time() - lastTime, 2)
         totalTime = round(time.time() - startTime, 2)
         print('Lap #%s: %s (%s)' % (lapNum, totalTime, lapTime), end='')
           lapNum += 1
           lastTime = time.time() # إعادة ضبط وقت الدورة الأخيرة
 except KeyboardInterrupt:
       # معالجة الاستثناء‫ Ctrl-C لمنع عرض رسالة الخطأ
       print('\nDone.')

إذا ضغط المستخدم على الاختصار CTRL-C لإيقاف المؤقت الزمني، فسيظهر الاستثناء KeyboardInterrupt، وسيتعطل البرنامج إذا لم يكن تنفيذه موجودًا ضمن تعليمة try، لذا غلّفنا هذا الجزء من البرنامج ضمن تعليمة try ➊، وسنعالج الاستثناء ضمن التعليمة except ➏، لذا ينتقل تنفيذ البرنامج إلى التعليمة except لطباعة الكلمة Done بدلًا من رسالة الخطأ KeyboardInterrupt عند الضغط على الاختصار CTRL-C ورفع الاستثناء. يكون التنفيذ ضمن حلقة لا نهائية ➋ حتى حدوث الاستثناء، حيث تستدعي هذه الحلقة الدالة input()‎ وتنتظر حتى يضغط المستخدم على مفتاح ENTER لإنهاء الدورة. إذا انتهت الدورة، فسنحسب المدة التي استغرقتها الدورة من خلال طرح وقت بدء الدورة lastTime من الوقت الحالي time.time()‎ ➌، ويمكننا حساب إجمالي الوقت المنقضي من خلال طرح وقت البدء الإجمالي للمؤقت الزمني startTime من الوقت الحالي ➍.

ستحتوي نتائج حسابات الوقت على العديد من الأعداد بعد الفاصلة العشرية مثل العد 4.766272783279419، لذا استخدمنا الدالة round()‎ لتقريب القيمة العشرية إلى عددين في التعلمتين ➌ و➍.

نطبع بعد ذلك رقم الدورة والوقت الإجمالي المنقضي ووقت الدورة ➎. يطبع المستخدم، الذي يضغط على مفتاح ENTER لاستدعاء الدالة input()‎، سطرًا جديدًا على الشاشة، لذا مرّر الوسيط end=''‎ إلى الدالة print()‎ لتجنب مضاعفة المسافة بين المخرجات. نتجهّز للدورة التالية بعد طباعة معلومات الدورة من خلال إضافة القيمة 1 إلى العدّاد lapNum ونضبط المتغير lastTime على الوقت الحالي الذي يمثّل وقت بدء الدورة التالية.

أفكار لبرامج مماثلة

يفتح تعقّب الوقت العديدَ من الاحتمالات أمام برامجك، حيث يمكنك كتابة هذه البرامج بنفسك بالرغم من أنه يمكنك تنزيل تطبيقاتٍ تنفّذ بعضًا منها، ولكن ستكون البرامج التي تكتبها بنفسك مجانية وغير مملوءة بالإعلانات والميزات عديمة الفائدة، لذلك جرّب كتابة برامج مماثلة تطبّق ما يلي:

  • إنشاء تطبيق جدول حضور زمني Timesheet بسيط يسجّل متى كتبتَ اسم شخصٍ ما ويستخدم الوقت الحالي لتسجيل زمن دخوله أو خروجه.
  • إضافة ميزة إلى برنامجك لعرض الوقت المنقضي منذ بدء عمليةٍ ما مثل عملية التنزيل التي تستخدم الوحدة requests.
  • التحقّق خلال فترات زمنية متقطعة من مدة تشغيل البرنامج ومنح المستخدم فرصة لإلغاء المهام التي تستغرق وقتًا طويلًا.

الوحدة datetime

تُعَد الوحدة time مفيدةً للحصول على علامة يونيكس الزمنية للعمل معها، ولكن إذا أردتَ عرض التاريخ بتنسيق أسهل أو إجراء العمليات الحسابية باستخدام التواريخ مثل معرفة التاريخ الذي كان قبل 205 يومًا أو التاريخ الذي سيكون بعد 123 يومًا من الآن، فيجب أن تستخدم الوحدة datetime.

تمتلك الوحدة datetime نوع البيانات datetime الخاص بها، حيث تمثل القيم التي نوعها datetime لحظةً محددة من الزمن. لندخِل الآن ما يلي في الصدفة التفاعلية:

   >>> import datetime
 >>> datetime.datetime.now()
 datetime.datetime(2024, 2, 27, 11, 10, 49, 55, 53)
 >>> dt = datetime.datetime(2023, 10, 21, 16, 29, 0)
 >>> dt.year, dt.month, dt.day
   (2023, 10, 21)
 >>> dt.hour, dt.minute, dt.second
   (16, 29, 0)

يؤدي استدعاء الدالة datetime.datetime.now()‎ ➊ إلى إعادة الكائن datetime ➋ للتاريخ والوقت الحاليين وفقًا لساعة حاسوبك، حيث يتضمن هذا الكائن السنة والشهر واليوم والساعة والدقيقة والثانية والميكروثانية للحظة الحالية. يمكنك أيضًا استرداد الكائن datetime للحظة معينة باستخدام الدالة datetime.datetime()‎ ➌ وتمرير أعداد صحيحة إليها، والتي تمثّل السنة والشهر واليوم والساعة والدقيقة والثانية للحظة التي تريدها، وتُخزَّن هذه الأعداد الصحيحة في سمات Attributes خاصة بالكائن datetime، وهذه السمات هي year و month و day ➍ و hour و minute و second ➎.

يمكن تحويل علامة يونيكس الزمنية إلى كائن datetime باستخدام الدالة datetime.datetime.fromtimestamp()‎، ويُحوَّل التاريخ والوقت الخاصين بكائن datetime إلى المنطقة الزمنية المحلية. إذًا أدخِل ما يلي في الصدفة التفاعلية:

>>> import datetime, time
>>> datetime.datetime.fromtimestamp(1000000)
datetime.datetime(1970, 1, 12, 5, 46, 40)
>>> datetime.datetime.fromtimestamp(time.time())
datetime.datetime(2023, 10, 21, 16, 30, 0, 604980)

يؤدي استدعاء الدالة datetime.datetime.fromtimestamp()‎ وتمرير القيمة 1000000 إليها إلى إعادة كائن datetime للحظة التي تكون بعد 1,000,000 ثانية من توقيت يونيكس، بينما يؤدي تمرير الدالة time.time()‎، التي تمثّل علامة يونيكس الزمنية للحظة الحالية، إلى الدالة datetime.datetime.fromtimestamp()‎ إلى إعادة كائن datetime للحظة الحالية، إذ يفعل التعبيران datetime.datetime.now()‎ و datetime.datetime.fromtimestamp(time.time())‎ الشيء نفسه، حيث يعطيان كائن datetime للوقت الحالي.

يمكنك مقارنة كائنات datetime مع بعضها البعض باستخدام عوامل المقارنة لمعرفة أيّ منها يسبق الآخر، حيث يكون لكائن datetime الأحدث القيمة الأكبر. لندخِل الآن ما يلي في الصدفة التفاعلية:

 >>> halloween2023 = datetime.datetime(2023, 10, 31, 0, 0, 0)
 >>> newyears2024 = datetime.datetime(2024, 1, 1, 0, 0, 0)
   >>> oct31_2023 = datetime.datetime(2023, 10, 31, 0, 0, 0)
 >>> halloween2023 == oct31_2023
   True
 >>> halloween2023 > newyears2024
   False
 >>> newyears2024 > halloween2023
   True
   >>> newyears2024 != oct31_2023
   True

أنشأنا كائن datetime للحظة الأولى (منتصف الليل) من 31 من الشهر العاشر من عام 2023، وخزّناه في المتغير halloween2023 ➊، ثم أنشأنا كائن datetime للحظة الأولى من 1 من الشهر الأول من عام 2024، وخزّناه في المتغير newyears2024 ➋، ثم أنشأنا كائنًا آخر لمنتصف ليل يوم 31 من الشهر العاشر من عام 2023، وخزّناه في المتغير oct31_2023. تُظهِر المقارنة بين المتغيرين halloween2023 و oct31_2023 أنهما متساويان ➌، وتُظهِر مقارنة المتغيرين newyears2024 و halloween2023 أن newyears2024 أكبر (أو أحدث) من halloween2023 ➍ ➎.

نوع البيانات timedelta

توفر الوحدة datetime أيضًا نوع البيانات timedelta الذي يمثل مدة زمنية بدلًا من توفير لحظة زمنية. لندخِل الآن ما يلي في الصدفة التفاعلية:

 >>> delta = datetime.timedelta(days=11, hours=10, minutes=9, seconds=8)
 >>> delta.days, delta.seconds, delta.microseconds
   (11, 36548, 0)
   >>> delta.total_seconds()
   986948.0
   >>> str(delta)
   '11 days, 10:09:08'

نستخدم الدالة datetime.timedelta()‎ لإنشاء كائن timedelta، حيث تأخذ هذه الدالة وسطاء الكلمات المفتاحية Keyword Arguments التي هي weeks و days و hours و minutes و seconds و milliseconds و microseconds، ولا توجد وسطاء الكلمات المفتاحية month و year، إذ يُعَد الشهر أو السنة مقدارًا متغيرًا من الزمن اعتمادًا على شهرٍ أو سنة معينة. يحتوي الكائن timedelta على المدة الإجمالية المُمثَّلة بالأيام والثواني والميكروثانية، حيث تُخزَّن هذه الأعداد في السمات days و seconds و microseconds. يعيد التابع total_seconds()‎ المدة بعدد الثواني فقط، بينما يؤدي تمرير كائن timedelta إلى الدالة str()‎ إلى إعادة تمثيل سلسلة نصية مُنسَّقة جيدًا وقابلة للقراءة البشرية لهذا الكائن.

مرّرنا في المثال السابق وسطاء الكلمات المفتاحية إلى الدالة datetime.timedelta()‎ لتحديد مدة 11 يومًا و10 ساعات و9 دقائق و8 ثوانٍ، وخزّنا كائن timedelta المُعاد في المتغير delta ➊. تخزِّن السمة days الخاصة بكائن timedelta القيمة 11، وتخزن السمة seconds القيمة 36548 (أي 10 ساعات و9 دقائق و8 ثوانٍ من خلال التعبير عنها بالثواني) ➋. يخبرنا استدعاء الدالة total_seconds()‎ أن 11 يومًا و10 ساعات و9 دقائق و8 ثوانٍ هي 986,948 ثانية، ويعيد تمرير كائن timedelta إلى الدالة str()‎ سلسلةً نصية تشرح المدة بوضوح.

يمكن استخدام المعاملات الحسابية لإجراء عملية حسابية للتاريخ على قيم datetime، فمثلًا أدخِل ما يلي في الصدفة التفاعلية لحساب التاريخ بعد 1000 يوم من الآن:

>>> dt = datetime.datetime.now()
>>> dt
datetime.datetime(2018, 12, 2, 18, 38, 50, 636181)
>>> thousandDays = datetime.timedelta(days=1000)
>>> dt + thousandDays
datetime.datetime(2021, 8, 28, 18, 38, 50, 636181)

أنشأنا أولًا كائن datetime للحظة الحالية وخزّناه في المتغير dt، ثم أنشأنا كائن timedelta لمدة 1000 يوم وخزّناه في المتغير thousandDays، ثم جمعنا dt و thousandDays للحصول على كائن datetime للتاريخ بعد 1000 يوم من الآن. تجري شيفرة بايثون عملية حسابية للتاريخ لمعرفة أن 1000 يوم بعد 2 من الشهر 12 من عام 2018 ستكون في 18 من الشهر الثامن من عام 2021. يُعَد ذلك مفيدًا لأنه يجب أن تتذكّر عدد الأيام في كل شهر والعامل المشترك للسنوات الكبيسة وغيرها من التفاصيل الصعبة عندما تحسب 1000 يوم بعد تاريخ معين، لذا تعالج الوحدة datetime جميع تلك الأمور نيابةً عنك.

يمكن جمع كائنات timedelta أو طرحها من كائنات datetime أو كائنات timedelta الأخرى باستخدام المعاملَين + و -، ويمكن ضرب كائن timedelta أو قسمته على عدد صحيح أو قيم عشرية باستخدام المعاملَين * و /. لندخِل مثلًا ما يلي في الصدفة التفاعلية:

 >>> oct21st = datetime.datetime(2019, 10, 21, 16, 29, 0)
 >>> aboutThirtyYears = datetime.timedelta(days=365 * 30)
   >>> oct21st
   datetime.datetime(2019, 10, 21, 16, 29)
   >>> oct21st - aboutThirtyYears
   datetime.datetime(1989, 10, 28, 16, 29)
   >>> oct21st - (2 * aboutThirtyYears)
   datetime.datetime(1959, 11, 5, 16, 29)

أنشأنا كائن datetime ليوم 21 من الشهر العاشر من عام 2019 ➊، وأنشأنا كائن timedelta لمدة 30 عامًا تقريبًا بافتراض أن السنة تتكون من 365 يومًا ➋. يؤدي طرح aboutThirtyYears من oct21st إلى الحصول على كائن datetime للتاريخ قبل 30 عامًا من تاريخ 21 من الشهر العاشر من عام 2019، ويؤدي طرح ‎2 * aboutThirtyYears من oct21st إلى إعادة كائن datetime للتاريخ قبل 60 عامًا من تاريخ 21 من الشهر العاشر من عام 2019.

الإيقاف المؤقت حتى تاريخ محدد

يتيح التابع time.sleep()‎ إيقافَ برنامجٍ ما مؤقتًا لعددٍ محدّدٍ من الثواني، حيث يمكنك إيقاف برامجك مؤقتًا حتى تاريخ محدّد باستخدام حلقة while، فمثلًا ستستمر الشيفرة البرمجية التالية في التكرار حتى يوم الهالوين من عام 2024:

import datetime
import time
halloween2024 = datetime.datetime(2024, 10, 31, 0, 0, 0)
while datetime.datetime.now() < halloween2016:
    time.sleep(1)

سيؤدي استدعاء time.sleep(1)‎ إلى إيقاف برنامج بايثون الخاص بك مؤقتًا حتى لا يضيع الحاسوب دورات معالجة لوحدة المعالجة المركزية بعد التحقق من الوقت مرارًا وتكرارًا، لذا تتحقق حلقة while من الشرط مرة واحدة في الثانية وتستمر إلى باقي البرنامج بعد يوم الهالوين من عام 2024 (أو أيّ تاريخ تبرمجه للتوقف).

تحويل كائنات datetime إلى سلاسل نصية

لا تُعَد علامات يونيكس الزمنية وكائنات datetime سهلة القراءة، لذا نستخدم التابع strftime()‎ لعرض كائن datetime بوصفها سلسلة نصية، حيث يشير الحرف f الموجود في اسم الدالة strftime()‎ إلى التنسيق format. يستخدم التابع strftime()‎ موجّهات Directives مشابهة لتنسيق سلاسل بايثون النصية، حيث يحتوي الجدول التالي على قائمة كاملة بموجّهات التابع strftime()‎:

موجّه التابع strftime()‎ معناه
‎%Y العام مع القرن مثل '2024'
‎%y العام بدون القرن من '00' إلى '99' (من عام 1970 إلى 2069 مثلًا)
‎%m الشهر كعدد عشري من '01' إلى '12'
‎%B اسم الشهر كاملًا مثل 'November'
‎%b اسم الشهر المختصر مثل 'Nov'
‎%d يوم من الشهر من '01' إلى '31'
‎%j يوم من السنة من '001' إلى '366'
‎%w يوم من الأسبوع من '0' (الأحد) إلى '6' (السبت)
‎%A الاسم الكامل ليوم من الأسبوع مثل 'Monday'
‎%a الاسم المختصر ليوم من الأسبوع مثل 'Mon'
‎%H الساعة (نظام 24 ساعة) من '00' إلى '23'
‎%I الساعة (نظام 12 ساعة) من '01' إلى '12'
‎%M الدقيقة من '00' إلى '59'
‎%S الثانية من '00' إلى '59'
‎%p صباحًا 'AM' أو مساءً 'PM'
‎%% المحرف '%' حرفيًا

مرّر سلسلة نصية ذات تنسيقٍ مخصَّص تحتوي على موجّهات التنسيق (مع أيّ خطوط مائلة ونقطتين وغير ذلك) إلى التابع strftime()‎، وسيعيد هذا التابع معلومات كائن datetime بوصفها سلسلة نصية مُنسَّقة. لندخِل الآن ما يلي في الصدفة التفاعلية:

>>> oct21st = datetime.datetime(2023, 10, 21, 16, 29, 0)
>>> oct21st.strftime('%Y/%m/%d %H:%M:%S')
'2023/10/21 16:29:00'
>>> oct21st.strftime('%I:%M %p')
'04:29 PM'
>>> oct21st.strftime("%B of '%y")
"October of '23"

خزّنا في المثال السابق كائن datetime ليوم 21 من الشهر العاشر من عام 2023 في الساعة 4:29 مساءً في المتغير oct21st. يعيد تمرير سلسلة التنسيق المخصَّصة '‎%Y/%m/%d %H:%M:%S' إلى التابع strftime()‎ سلسلةً نصية تحتوي على القيم 2023 و10 و21 المفصولة بخطوط مائلة والقيم 16 و29 و00 المفصولة بنقطتين، ويؤدي تمرير السلسلة النصية '‎%I:%M% p' إلى إعادة '‎04:29 PM'، ويؤدي تمرير السلسلة النصية "‎%B of '%y" إلى إعادة ‎"October of '23"‎. لاحظ أننا لا نضع datetime.datetime قبل التابع strftime()‎.

تحويل السلاسل النصية إلى كائنات datetime

إذا كان لديك سلسلة نصية تمثّل معلومات التاريخ مثل '2023/10/21‎ 16:29:00' أو 'October 21, 2023' وتريد تحويلها إلى كائن datetime، فاستخدم الدالة datetime.datetime.strptime()‎، حيث تُعَد هذه الدالة عكس التابع strftime()‎. يجب تمرير سلسلة تنسيق مُخصَّصة تستخدم الموجّهات نفسها التي يستخدمها التابع strftime()‎ إلى الدالة strptime()‎ حتى تعرف كيفية تحليل السلسلة النصية وفهمها، ويشير الحرف p الموجود في اسم الدالة strptime()‎ إلى التحليل Parse. لندخِل الآن ما يلي في الصدفة التفاعلية:

 >>> datetime.datetime.strptime('October 21, 2023', '%B %d, %Y')
   datetime.datetime(2023, 10, 21, 0, 0)
   >>> datetime.datetime.strptime('2023/10/21 16:29:00', '%Y/%m/%d %H:%M:%S')
   datetime.datetime(2023, 10, 21, 16, 29)
   >>> datetime.datetime.strptime("October of '23", "%B of '%y")
   datetime.datetime(2023, 10, 1, 0, 0)
   >>> datetime.datetime.strptime("November of '63", "%B of '%y")
   datetime.datetime(2063, 11, 1, 0, 0)

يمكن الحصول على كائن datetime من السلسلة النصية 'October 21, 2023' من خلال تمرير هذه السلسلة كوسيطٍ أول إلى الدالة strptime()‎ وتمرير سلسلة التنسيق المُخصصة المقابلة للسلسلة النصية 'October 21, 2023' كوسيطٍ ثانٍ ➊. يجب أن تتطابق السلسلة النصية التي تحتوي على معلومات التاريخ مع سلسلة التنسيق المخصصة تمامًا، وإلّا سيرفع بايثون استثناء ValueError.

مراجعة لدوال بايثون الخاصة بالوقت

يمكن أن تتضمن التواريخ والأوقات في بايثون عددًا من أنواع البيانات والدوال المختلفة، لذا سنوضح فيما يلي الأنواع الثلاثة المختلفة من القيم المُستخدَمة لتمثيل الوقت:

  • علامة يونيكس الزمنية التي تستخدمها الوحدة time، وهي قيمة عشرية أو صحيحة لعدد الثواني منذ الساعة 12 صباحًا في 1 من الشهر الأول من عام 1970 بالتوقيت العالمي المنسق.
  • كائن datetime الخاص بالوحدة datetime، والذي يحتوي على أعداد صحيحة مخزَّنة في السمات year و month و day و hour و minute و second.
  • كائن timedelta الخاص بالوحدة datetime، والذي يمثّل مدة زمنية وليس لحظة مُحدَّدة.

إليك مراجعة لدوال الوقت ومعاملاتها والقيم التي تعيدها:

  • time.time()‎: تعيد هذه الدالة القيمة العشرية لعلامة يونيكس الزمنية للحظة الحالية.
  • time.sleep(seconds)‎:توقِف هذه الدالة البرنامج لعددٍ من الثواني التي يحدّدها الوسيط seconds.
  • datetime.datetime(year, month, day, hour, minute, second)‎: تعيد هذه الدالة كائن datetime للحظة التي تحدّدها وسطاؤها. إذا لم تتوفّر قيم للوسطاء hour أو minute أو second، فستكون قيمها الافتراضية 0.
  • datetime.datetime.now()‎: تعيد هذه الدالة كائن datetime للحظة الحالية.
  • datetime.datetime.fromtimestamp(epoch)‎: تعيد هذه الدالة كائن datetime للحظة التي يمثلها وسيط العلامة الزمنية epoch.
  • datetime.timedelta(weeks, days, hours, minutes, seconds, milliseconds, microseconds)‎: تعيد هذه الدالة كائن timedelta الذي يمثل مدة زمنية، وتُعَد وسطاء الكلمات المفتاحية لهذه الدالة اختيارية ولا تتضمن month أو year.
  • total_seconds()‎: يعيد هذا التابع الخاص بكائنات timedelta عدد الثواني التي يمثّلها كائن timedelta.
  • strftime(format)‎: يعيد هذا التابع سلسلة نصية للوقت الذي يمثّله كائن datetime بتنسيقٍ مخصَّص يعتمد على سلسلة التنسيق format. اطّلع على الجدول السابق للحصول على تفاصيل التنسيق.
  • datetime.datetime.strptime(time_string, format)‎: تعيد هذه الدالة كائن datetime للحظة التي يحدّدها الوسيط time_string، وتُحلَّل باستخدام وسيط سلسلة التنسيق format. اطّلع على الجدول السابق للحصول على تفاصيل التنسيق.

الخلاصة

يُعَد توقيت يونيكس (1 من الشهر الأول من عام 1970 عند منتصف الليل بالتوقيت العالمي المنسَّق) وقتًا مرجعيًا معياريًا للعديد من لغات البرمجة بما في ذلك لغة بايثون. تعيد الوحدة الخاصة بالدالة time.time()‎ علامة يونيكس الزمنية (أي قيمة عشرية لعدد الثواني منذ توقيت يونيكس)، ولكن تُعَد الوحدة datetime أفضل لإجراء العمليات الحسابية الرياضية على التاريخ وتنسيق أو تحليل السلاسل النصية باستخدام معلومات التاريخ. ستوقَِف الدالة time.sleep()‎ التنفيذ (أي لن تعود) لعددٍ معين من الثواني، حيث يمكنك استخدام ذلك لإضافة فترات توقف مؤقتة إلى برنامجك.

ترجمة -وبتصرُّف- للقسم Keeping Time من مقال Keeping Time, Scheduling Tasks, and Launching Programs لصاحبه Al Sweigart.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...