حافظ على قيمة النشر التي تقتصر على التاريخ بقراءتها كتاريخ تقويمي والإبقاء على ذلك التاريخ بوصفه المرجع المعتمد. إذا كان التصدير يتطلب طابعًا زمنيًا بتوقيت UTC، فأضف اصطلاحًا صريحًا يجعل منتصف الليل بتوقيت UTC هو الوقت المعتمد. يوضح هذا الدليل العملي في Terminal على جهاز Mac الفرق، ويختبر التحويل ذهابًا وإيابًا.
حدّد المعنى الفعلي لحقل النشر
لنفترض أن قائمة المنشورات تحتوي على القيمة الاصطناعية 2028-06-15. مهمتك هي التحقق من هذه القيمة وتجهيزها للتصدير دون أن تعرض تاريخ 14 يونيو عن طريق الخطأ. قبل اختيار المحلّل، حدّد ما إذا كان الحقل يسجل يوم النشر أم لحظة النشر الفعلية.
لهذه المفاهيم الأربعة أدوار مختلفة:
| المفهوم | مثال اصطناعي | المعنى |
|---|---|---|
| التاريخ المدني | 2028-06-15 |
يوم تقويمي بلا وقت أو إزاحة |
| اللحظة الزمنية | 2028-06-15T00:00:00+00:00 |
لحظة محددة معبّر عنها بتوقيت UTC |
| إزاحة UTC | +09:00 |
الفرق بين قراءة الساعة المحلية وتوقيت UTC |
| المنطقة الزمنية المسماة | America/Los_Angeles |
معرّف يُستخدم للحصول على قواعد المنطقة الزمنية السارية |
يعرّف RFC 3339 قيمة full-date على نحو مستقل عن date-time؛ إذ تضيف قواعد صيغة الطابع الزمني وقتًا وإزاحة إلى التاريخ. لذلك، يفتقر تاريخ النشر المجرد إلى المعلومات اللازمة لتحديد لحظة النشر. واختيار منتصف الليل يضيف معلومات لم تكن موجودة في المدخل. RFC 3339، القسم 5.6
كما تتضمن المنطقة الزمنية المسماة معلومات أكثر من إزاحة رقمية واحدة. توضح وثائق Python أن zoneinfo يمكن أن تستخدم إزاحات مختلفة أثناء الانتقال إلى التوقيت الصيفي. ولا حاجة إلى تطبيق هذه القواعد على تسمية تقتصر على التاريخ. Python: دعم المناطق الزمنية وفق IANA
استخدم قاعدة القرار التالية قبل التصدير:
- معنى الحقل «نُشر في هذا اليوم»: احتفظ بقيمة تقتصر على التاريخ في التخزين والعرض.
- الصيغة المستقبِلة تتطلب طابعًا زمنيًا: احتفظ بالتاريخ واشتق منه قيمة حاملة عند منتصف الليل بتوقيت UTC وفق اصطلاح موثّق.
- معنى الحقل «نُشر في هذه اللحظة»: احصل على الوقت والإزاحة الفعليين، أو على الوقت والمنطقة الزمنية المسماة اللازمين لتحديد تلك اللحظة.
يفيد اصطلاح القيمة الحاملة في التوافق، لكنه لا يستعيد وقت نشر مجهولًا. ويُظهر اسم حقل مثل utc_carrier هذا القيد؛ أما تسميته published_at فستُوحي بوجود معلومات لم يقدّمها المصدر قط.
افهم أين يظهر خطأ اليوم السابق
لنفترض وجود مساري معالجة محتملين للقيمة 2028-06-15. في المسار الأول، يختلق البرنامج منتصف الليل عند الإزاحة الثابتة +09:00، ثم يحوّل تلك اللحظة إلى توقيت UTC. تكون النتيجة 2028-06-14T15:00:00+00:00: فالطرح لتسع ساعات يتجاوز حدود اليوم.
في المسار الثاني، ينشئ البرنامج عمدًا منتصف الليل بتوقيت UTC: 2028-06-15T00:00:00+00:00. وعند عرض اللحظة نفسها باستخدام الإزاحة الثابتة -07:00، تكون النتيجة 2028-06-14T17:00:00-07:00. هذه حسابات توضيحية للإزاحة، وليست ادعاءات بشأن إزاحة منطقة زمنية مسماة في ذلك التاريخ.
يحافظ كلا الحسابين على اللحظة الزمنية الخاصة به. ولا يحافظ أي منهما على تسمية التاريخ التقويمي الأصلية عند العرض في كل منطقة زمنية. توثّق Python أن astimezone() تعدّل حقول الساعة مع الحفاظ على وقت UTC الذي تمثله. Python: datetime.astimezone()
عمليًا، ينبغي أن يتبع التحليل والعرض عقدًا مشتركًا. إذا حُوّل تاريخ إلى قيمة حاملة عند منتصف الليل بتوقيت UTC، فاستخرج حقوله التقويمية بتوقيت UTC. وإذا أردت بقاء تسمية النشر بلا تغيير أينما فُتح التصدير، فاعرض التاريخ المدني المحتفَظ به.
لا تفترض أن كل لغة توفر المعلومات الناقصة بالطريقة نفسها. تحدد مواصفة ECMAScript أن صيغ التاريخ التي لا تتضمن إزاحة تُفسّر على أنها بتوقيت UTC، بينما تُفسّر صيغ التاريخ والوقت التي لا تتضمن إزاحة على أنها بالتوقيت المحلي. لذلك، قد تؤدي إضافة T00:00:00 إلى سلسلة نصية إلى تغيير تفسيرها في JavaScript. ECMAScript: Date.parse
نفّذ فحصًا كاملًا لتاريخ النشر في Terminal على جهاز Mac
يتحقق هذا الدليل من ثلاثة تواريخ اصطناعية، ويطبع معاينة مفصولة بعلامات تبويب، ويختبر رفض المدخلات ذات التنسيق غير الصحيح. ولا يعدّل قائمة منشورات أو ينشئ ملف تصدير.
في Finder، افتح /Applications/Utilities، ثم انقر مرتين على Terminal. توثّق Apple هذه الطريقة على أنها طريقة مدعومة لفتح تطبيق سطر الأوامر. Apple: فتح Terminal أو إنهاؤه على Mac
شغّل الأمر التالي للتحقق من المفسّر:
python3 --version
استخدم Python 3.11 أو إصدارًا أحدث لهذا الدليل. إذا لم يكن python3 متاحًا أو أظهر إصدارًا أقدم، فاتبع تعليمات التثبيت الرسمية لنظام macOS قبل المتابعة، ثم أعد فتح Terminal وتحقق مجددًا. توثّق Python كلًا من أداة التثبيت لنظام macOS وطريقة تشغيل البرامج النصية باستخدام python3. Python: استخدام Python على macOS
الصق الكتلة كاملة أدناه، بما في ذلك PY الأخيرة، ثم اضغط على Return. تخبر الوسيطة - Python بقراءة البرنامج من الإدخال القياسي. تتضمن الكتلة جميع بيانات العينة وعمليات الاستيراد. Python: سطر الأوامر والبيئة
python3 - <<'PY'
import re
from datetime import date, datetime, time, timezone
def parse_publication_date(text):
if not isinstance(text, str) or re.fullmatch(
r"[0-9]{4}-[0-9]{2}-[0-9]{2}", text
) is None:
raise ValueError("Expected YYYY-MM-DD")
return date.fromisoformat(text)
def utc_carrier(day):
return datetime.combine(day, time(0), tzinfo=timezone.utc)
samples = ["2028-02-29", "2028-06-15", "2028-12-31"]
parsed = [(text, parse_publication_date(text)) for text in samples]
print("publication_date\tutc_carrier")
for original, day in parsed:
carrier = utc_carrier(day)
assert day.isoformat() == original
assert carrier.astimezone(timezone.utc).date() == day
print(day.isoformat(), carrier.isoformat(timespec="seconds"), sep="\t")
for invalid in [
"2027-02-29",
"2028-6-15",
"2028-06-15T00:00:00",
" 2028-06-15",
]:
try:
parse_publication_date(invalid)
except ValueError:
pass
else:
raise AssertionError(f"Unexpected acceptance: {invalid!r}")
print("Round-trip and rejection checks passed.")
PY
الناتج المتوقع هو:
publication_date utc_carrier
2028-02-29 2028-02-29T00:00:00+00:00
2028-06-15 2028-06-15T00:00:00+00:00
2028-12-31 2028-12-31T00:00:00+00:00
Round-trip and rejection checks passed.
نُفّذ المثال وحسابا الإزاحة الثابتة بنجاح باستخدام مفسّر Python المتاح. أما تعليمات فتح Terminal والتحقق من المفسّر الخاصة بجهاز Mac فتتبع الوثائق الرسمية المرتبطة.
لماذا يحافظ المثال على يوم النشر
يتحقق المحلّل من أمرين كلٌّ على حدة: شكل السلسلة النصية الدقيق وصحة التاريخ التقويمية. يفرض التعبير النمطي أربعة أرقام للسنة، ورقمين للشهر، ورقمين لليوم. ثم يرفض محلّل التاريخ التواريخ المستحيلة. وهذا يمنع عمود النشر من قبول الطوابع الزمنية أو المسافات المحيطة أو المدخلات المختصرة دون تنبيه.
يهمّ التحقق الصريح من الشكل لأن date.fromisoformat() يقبل أيضًا تمثيلات ISO أخرى، ومنها التواريخ المدمجة وتواريخ الأسابيع. بعد ذلك، يضيف datetime.combine() منتصف الليل وتوقيت UTC عن قصد. Python: أنواع التاريخ والوقت الأساسية
يحلّل البرنامج قائمة العينات كاملة قبل طباعة الترويسة. إذا استبدلتَ إحدى العينات بقيمة غير صالحة، يتوقف التنفيذ قبل ظهور أي صفوف للمعاينة. أما اختبارات المدخلات غير الصالحة المتعمدة في النهاية فهي اختبارات منفصلة؛ إذ يُلتقط الاستثناء المتوقع كي يمكن التحقق من جميع حالات الرفض.
يعبّر اختبارا التحويل ذهابًا وإيابًا عن العقد. يتحقق الأول من أن التحليل والتنسيق يعيدان تسمية التاريخ الأصلية. ويتحقق الثاني من أن القيمة الحاملة المشتقة تُنتج التاريخ نفسه عند تفسيرها بتوقيت UTC. ويختبران معًا مهمة الحفاظ الدقيقة، بدلًا من الاكتفاء بالتحقق من إمكان إنشاء طابع زمني ما.
يستخدم الناتج +00:00 صراحةً. ويسمح RFC 3339 أيضًا باستخدام Z بوصفه محدد إزاحة UTC، لكن إضافة أي من اللاحقتين إلى تاريخ مجرد لا توفر مكوّن الوقت الناقص. احتفظ بالصيغة التي تقتصر على التاريخ أو أنشئ الطابع الزمني الكامل عن قصد. RFC 3339، القسم 5.6
شخّص سبب استمرار تغيّر التاريخ في التصدير
إذا أظهرت معاينة لاحقة اليوم السابق، فافحص القيم عند كل حد فاصل. استخدم العينة الوسطى الاصطناعية، 2028-06-15، لمقارنة كل مرحلة بتسمية واحدة معروفة.
| نقطة الفحص | المتوقع وفق اصطلاح القيمة الحاملة | ما قد يدل عليه الاختلاف |
|---|---|---|
| حقل النشر الأصلي | 2028-06-15 |
تغيّر المدخل قبل تحليله |
| التاريخ المحلّل بعد تنسيقه كنص | 2028-06-15 |
غيّر التحليل أو التطبيع التسمية |
| قيمة UTC الحاملة المشتقة | 2028-06-15T00:00:00+00:00 |
أُدخل وقت أو إزاحة مختلفة |
| التاريخ المستعاد بتوقيت UTC | 2028-06-15 |
استخدم التحويل أو الاستخراج عقدًا غير صحيح |
| تسمية النشر المعروضة للقارئ | 2028-06-15 |
قد يعرض العارض القيمة الحاملة في منطقة زمنية أخرى |
افحص العارض بمعزل عن المحلّل. فقد تؤدي قيمة UTC الحاملة الصحيحة إلى يوم تقويمي مختلف عند عرضها وفق إعداد المنطقة الزمنية المحلية. أما تسمية النشر، فزوّد العارض بقيمة التاريخ المحتفَظ بها التي تقتصر على التاريخ. وإذا كان يقبل الطوابع الزمنية فقط، فاستخدم خيار عرض بتوقيت UTC موثّقًا وتحقق من النتيجة.
إذا كانت الأداة المستقبِلة لا تدعم سوى اللحظات الزمنية وتعرضها دائمًا بالتوقيت المحلي، فلا يمكن لاصطلاح منتصف الليل بتوقيت UTC ضمان بقاء تسمية التاريخ بلا تغيير. احتفظ بعمود نصي منفصل للتاريخ فقط، أو استخدم حقلًا للتاريخ فقط تدعمه الأداة، أو اختر عارضًا يوفّر تنسيقًا صريحًا بتوقيت UTC. وينبع هذا القيد من حسابات الإزاحة أعلاه؛ فلا يمكن لتغيير المحلّل وحده إزالته.
وتجنّب أيضًا التعامل مع طابع زمني موجود كما لو كان مدخلًا لا يتضمن سوى التاريخ. بالنسبة إلى لحظة زمنية فعلية، يعني تغيير منطقتها الزمنية تحويلها. تميّز Python هذه العملية عن استبدال tzinfo، الذي يرفق معلومات المنطقة الزمنية من دون تعديل حقول الساعة. Python: سلوك تحويل المنطقة الزمنية
بالنسبة إلى قائمة منشوراتك، احتفظ بـpublication_date بوصفه القيمة التقويمية المعتمدة. واشتق قيمة UTC حاملة فقط عند واجهة تتطلبها، وأرفق اصطلاحها بالحقل، وتحقق من استخراج التاريخ بتوقيت UTC قبل الوثوق بالمعاينة. يوفّر ذلك طريقة قابلة للتكرار للحفاظ على اليوم الوارد دون اختلاق لحظة نشر.
المصادر
- فتح Terminal أو إنهاؤه على Mac — Apple.
- استخدام Python على macOS — Python Software Foundation.
- سطر الأوامر والبيئة — Python Software Foundation.
- datetime — أنواع التاريخ والوقت الأساسية — Python Software Foundation.
- zoneinfo — دعم المناطق الزمنية وفق IANA — Python Software Foundation.
- RFC 3339: التاريخ والوقت على الإنترنت: الطوابع الزمنية — RFC Editor.
- مواصفة لغة ECMAScript: الأعداد والتواريخ — Ecma International / TC39.