لطرح عدد محدد من الساعات من طابع زمني بالتوقيت العالمي المنسق (UTC) على جهاز Mac، حلّله باستخدام إزاحته عن UTC، واطرح مدة زمنية، وأخرج النتيجة صراحةً بالتوقيت UTC. يستخدم سير العمل هذا في Terminal لغة Python وتاريخ نشر افتراضيًا.
المهمة هنا محددة: إرجاع طابع زمني للنشر بمقدار عدد صحيح غير سالب من الساعات مع إبقاء كل من الإدخال والإخراج بالتوقيت UTC. على سبيل المثال، طرح سبع ساعات من 2026-05-12T02:30:00Z ينتج عنه 2026-05-11T19:30:00Z.
تتبع «الدقة» نموذج Python الموثق لكائن datetime: الساعة الواحدة تساوي 3,600 ثانية، ولا تُمثَّل الثواني الكبيسة. لذا يناسب سير العمل هذا الطوابع الزمنية المعتادة للنشر؛ أما الحسابات التي يلزمها احتساب الثواني الكبيسة فتتطلب نموذجًا زمنيًا مختلفًا. وثائق Python datetime
ما نوع التاريخ الذي تبدأ به؟
قبل الحساب، ميّز بين تاريخ تقويمي وطابع زمني. تاريخ مثل 2026-05-12 لا يحدد وقت النشر. فإضافة منتصف الليل أو افتراض المنطقة الزمنية المحلية لجهاز Mac ستُدخل معلومات لم يوفرها الإدخال أصلًا.
| المفهوم | مثال افتراضي | ما الذي يوضحه |
|---|---|---|
| تاريخ مدني | 2026-05-12 |
يوم تقويمي من دون وقت أو إزاحة |
| تاريخ ووقت محليان | 2026-05-12T02:30:00 |
حقول الساعة من دون سياق كافٍ لتحديد لحظة زمنية |
| لحظة زمنية معبّر عنها بالتوقيت UTC | 2026-05-12T02:30:00Z |
نقطة زمنية محددة |
| إزاحة رقمية | +00:00 |
الفرق المحدد عن UTC |
| منطقة زمنية مسماة | Europe/Paris |
قواعد ربط قراءات الساعة المحلية بالتوقيت UTC |
للإزاحة والمنطقة الزمنية المسماة غرضان مختلفان. تصف الإزاحة الرقمية علاقة الطابع الزمني بالتوقيت UTC؛ أما المنطقة الزمنية المسماة فتوفّر قواعد قد تتغير حسب التاريخ. يعرّف RFC 9557 هذه الفروق ويوضح لماذا قد تقابل بعض قراءات الساعة المحلية صفرًا أو أكثر من لحظة زمنية. RFC 9557، التعريفات
استخدم طابعًا زمنيًا كاملًا لهذه المهمة. يقبل البرنامج أدناه T بالأحرف الكبيرة، والثواني، وجزءًا كسريًا اختياريًا من ثانية يتراوح بين رقم واحد وستة أرقام، وإما Z أو +00:00. هذه مجموعة فرعية محدودة عمدًا من RFC 3339، إذ تسمح قواعد صياغة الطابع الزمني فيه أيضًا بإزاحات أخرى وبأرقام كسرية إضافية. RFC 3339، تنسيق التاريخ والوقت
كيف تطرح الساعات في Terminal؟
جهّز Python على جهاز Mac
افتح Finder، وانتقل إلى /Applications/Utilities، ثم انقر نقرًا مزدوجًا على Terminal. توثّق Apple هذه الطريقة لفتح تطبيق سطر الأوامر. فتح Terminal أو إنهاؤه على Mac
أدخل هذا الأمر واضغط على Return:
python3 --version
استخدم Python 3.11 أو إصدارًا أحدث في هذا الشرح. إذا لم يتوفر مفسّر مناسب، فاتبع تعليمات التثبيت الرسمية لنظام macOS: نزّل مثبّت Python مدعومًا من صفحة تنزيلات macOS المرتبطة، وافتح ملف .pkg، وأكمل خطوات التثبيت الموثقة. ثم افتح نافذة Terminal جديدة وتحقق من الإصدار مجددًا. توثّق Python التثبيت وتشغيل Python من الصدفة. استخدام Python على macOS
نفّذ العملية الحسابية كاملة
انسخ الكتلة كاملةً أدناه إلى Terminal، بما فيها السطران الأول والأخير، ثم اضغط على Return. لإجراء عملية حسابية أخرى، غيّر source_timestamp وhours_to_subtract فقط قبل اللصق. أبقِ الطابع الزمني بين علامتي اقتباس، وأدخل الساعات كعدد صحيح.
python3 - <<'PY'
import re
from datetime import datetime, timedelta, timezone
source_timestamp = "2026-05-12T02:30:00Z"
hours_to_subtract = 7
def subtract_utc_hours(text, hours):
if type(hours) is not int or hours < 0:
raise ValueError("Hours must be a non-negative whole number.")
match = re.fullmatch(
r"[0-9]{4}-[0-9]{2}-[0-9]{2}T"
r"[0-9]{2}:[0-9]{2}:[0-9]{2}"
r"(?P<fraction>\.[0-9]{1,6})?(?:Z|\+00:00)",
text,
)
if match is None:
raise ValueError(
"Use YYYY-MM-DDTHH:MM:SS, optionally .ffffff, "
"ending in Z or +00:00."
)
normalized = text[:-1] + "+00:00" if text.endswith("Z") else text
start = datetime.fromisoformat(normalized).astimezone(timezone.utc)
try:
result = start - timedelta(hours=hours)
except OverflowError as exc:
raise ValueError(
"The duration or result is outside the supported range."
) from exc
# Whole-hour subtraction leaves the fractional second unchanged.
seconds_text = result.isoformat(timespec="seconds")
return seconds_text[:-6] + (match.group("fraction") or "") + "Z"
try:
print(subtract_utc_hours(source_timestamp, hours_to_subtract))
except ValueError as exc:
raise SystemExit(f"Cannot subtract: {exc}")
PY
الناتج للطابع الزمني الافتراضي للنشر المُدخل هو:
2026-05-11T19:30:00Z
هذا برنامج كامل يستخدم مكتبة Python القياسية. يطبع الطابع الزمني المحسوب من دون إنشاء ملف. انسخ النتيجة إلى حقل تاريخ النشر أو المستند الذي تُعدّه.
تسلسل واجهات البرمجة هو datetime.fromisoformat()، والتحويل إلى timezone.utc، وطرح timedelta(hours=hours)، ثم الإخراج عبر isoformat(). توثّق Python عمليات التحليل والمناطق الزمنية والمدد والتنسيق هذه. واجهات Python datetime
كيف يحافظ البرنامج على UTC والثواني الكسرية؟
يشترط التحقق من الإدخال تمثيلًا صريحًا للتوقيت UTC. ويُرفض الطابع الزمني الذي لا يحتوي على إزاحة فورًا، لذا لا يحتاج البرنامج إلى استنتاج منطقة زمنية من إعدادات جهاز Mac. وتُحلَّل كلتا اللاحقتين المقبولتين على أنهما طوابع زمنية بإزاحة صفر، ويُكتب الإخراج دائمًا باستخدام Z.
الحفاظ على UTC لا يعني الاحتفاظ بكل محرف من السلسلة الأصلية. فالإدخال الذي ينتهي بـ +00:00 يعود منتهيًا بـ Z. تحتفظ النتيجة بتمثيل UTC، بينما يرجع التاريخ والوقت بمقدار المدة المطلوبة.
يحافظ البرنامج أيضًا على النص المقدم للثواني الكسرية. فطرح ساعات كاملة يُبقي هذا الجزء كما هو، لذا تظل .120 على حالها لتصبح .120 بدلًا من أن تتحول إلى .12 أو تختفي. وتُرفض المدخلات التي تتجاوز ستة أرقام كسرية بدلًا من تقليصها.
هناك تفصيل مهم في المعايير: تمثل Z إزاحة صفرية عن UTC، لكنها لا تحدد المنطقة الزمنية لموقع المصدر. يحدّث RFC 9557 تفسير RFC 3339 لـ Z بحيث يسمح بأن تكون الإزاحة المحلية غير معروفة. يقبل هذا البرنامج Z و+00:00 عمدًا؛ أما رفض -00:00 فهو خيار في سياسة الإدخال. RFC 9557، تحديث RFC 3339
كيف تتحقق من النتيجة قبل استخدامها؟
ابدأ بحساب يتجاوز منتصف الليل. في المثال الرئيسي، يؤدي الرجوع ساعتين إلى 00:30:00 في 12 مايو؛ والرجوع خمس ساعات أخرى يصل إلى 19:30:00 في 11 مايو. إذا بقيت النتيجة في 12 مايو فستكون غير صحيحة.
توفّر هذه الأمثلة الافتراضية عمليات تحقق إضافية. غيّر قيمتي الإدخال في البرنامج الكامل لمطابقة كل صف.
| إدخال UTC | الساعات المطروحة | ناتج UTC المتوقع |
|---|---|---|
2026-05-12T02:30:00Z |
7 | 2026-05-11T19:30:00Z |
2026-01-01T00:15:00+00:00 |
1 | 2025-12-31T23:15:00Z |
2028-03-01T00:30:00Z |
1 | 2028-02-29T23:30:00Z |
2026-05-12T02:30:00.120Z |
7 | 2026-05-11T19:30:00.120Z |
2026-05-12T02:30:00Z |
0 | 2026-05-12T02:30:00Z |
في المثال الرئيسي، تساوي المدة سبعة أضعاف 3,600، أي 25,200 ثانية. وتظل الدقائق والثواني كما هي لأن المدة المطلوبة تتكون من ساعات كاملة فقط. وقد يتغير التاريخ عند تجاوز منتصف الليل أو حدود الشهر أو حدود السنة.
ماذا تفعل عندما يُرفض الإدخال؟
استخدم الرفض كخطوة تشخيصية. عالج المعلومات الناقصة أو الدقة غير المدعومة قبل إعادة المحاولة.
- المتوفر تاريخ فقط: احصل على وقت النشر المقصود وإزاحته. فالتاريخ المدني وحده لا يحدد اللحظة الزمنية التي تبدأ منها.
- الطابع الزمني بلا إزاحة: تأكد مما إذا كان يمثل UTC أو التوقيت المحلي قبل إضافة لاحقة.
- للطابع الزمني إزاحة غير صفرية: حوّل اللحظة التي يمثلها إلى UTC أولًا. فتغيير اللاحقة وحدها يغيّر معناه.
- هناك أكثر من ستة أرقام كسرية: استخدم أداة تحتفظ بهذه الدقة، أو حدّد سياسة تقريب صريحة قبل استخدام سير العمل هذا.
- الساعات سالبة أو كسرية: أدخل عددًا صحيحًا غير سالب. يطبّق هذا البرنامج عمدًا طرح الساعات الكاملة.
- حقول التقويم غير صالحة: صحح القيمة المصدر. وسيُرفض تاريخ مستحيل مثل 30 فبراير.
تدعم Python السنوات من 1 إلى 9999 في datetime؛ ويفشل الطرح إذا تجاوز هذا النطاق. كما يرفض نموذج datetime فيها قيمة ثوانٍ 60، رغم أن RFC 3339 يسمح بهذه القيمة للثانية الكبيسة في شروط محددة. حدود Python datetime، RFC 3339، القيود
إذا كان مطلبك الفعلي هو «الوقت المحلي نفسه في اليوم السابق»، فاستخدم سير عمل تقويميًا بمنطقة زمنية مسماة. قد تغيّر المناطق الزمنية المسماة الإزاحة عند الانتقال إلى التوقيت الصيفي، لذا قد تختلف هذه المهمة عن طرح 24 ساعة منقضية. تعرض وثائق zoneinfo في Python أمثلة على الحساب عبر مثل هذه الانتقالات. دعم مناطق IANA الزمنية في Python
لطابع زمني للنشر مُعبّر عنه أصلًا بالتوقيت UTC، أبقِ العملية محددة: تحقّق من الإدخال، واطرح مدة الساعات الكاملة، واحتفظ بلاحقة UTC الصريحة في القيمة التي تنسخها. تحقّق من حدود التاريخ ودقة الجزء الكسري قبل استخدام النتيجة.
المصادر
- datetime — أنواع التاريخ والوقت الأساسية — مؤسسة Python للبرمجيات.
- استخدام Python على macOS — مؤسسة Python للبرمجيات.
- فتح Terminal أو إنهاؤه على Mac — Apple.
- RFC 3339: التاريخ والوقت على الإنترنت: الطوابع الزمنية — محرر RFC.
- RFC 9557: التاريخ والوقت على الإنترنت: طوابع زمنية بمعلومات إضافية — محرر RFC.
- zoneinfo — دعم مناطق IANA الزمنية — مؤسسة Python للبرمجيات.