يخزّن كل حاسوب تقريبًا الوقت رقمًا واحدًا: كم ثانية مضت منذ بداية 1970 تمامًا، مقيسة بتوقيت UTC. هذه هي الفكرة كلها. لا مناطق زمنية، ولا تقاويم، ولا تنسيق — عدد صحيح واحد يزحف صعودًا.
هذا تصميم صحيح بالنسبة إلى حاسوب وغير مقروء بالنسبة إلى إنسان، ولهذا يظهر الرقم باستمرار في السجلّات وقواعد البيانات وواجهات API وملفات التصدير، ولهذا صار تحويله مهمّة شائعة.
لماذا 1970
لا سبب عميق. كان Unix يُبنى في مختبرات Bell عند مطلع السبعينيات، واحتاج أحدهم نقطة بداية حديثة ومستديرة.
كانت النسخة الأولى تعدّ أجزاء الستّين من الثانية، وهو ما يبدو دقيقًا وقد فاض عن مداه المتاح في نحو سنتين ونصف — فصارت الوحدة ثوانيَ كاملة وانتقل المبدأ إلى بداية 1970. تلك المصادفة هي سبب قياس كل طابع زمني ستراه من صباح خميس قبل نيّف وخمسين عامًا.
ثوانٍ أم ميلي ثانية — الخطأ الذي يقع فيه الجميع مرّة
هذا هو الفخّ العملي، وكشفه سهل متى عرفت الشكلين.
عشر خانات تعني ثواني. لكن JavaScript يعمل بالميلي ثانية، وكذلك Java وكثير ممّا بُني عليهما — ثلاث عشرة خانة تعني ميلي ثانية.
أعطِ قيمة بالميلي ثانية لشيء يتوقّع ثواني، فيقرؤها تاريخًا قرب سنة 50,000. أعطِ ثواني لشيء يتوقّع ميلي ثانية، فتهبط في يناير 1970. لا يُخرج أيّهما خطأً؛ كلاهما يُخرج تاريخًا خاطئًا بثقة، وهذا أسوأ.
المحوّل الجدير بالاستعمال يخبرك بما افترضه بدل أن يختار بصمت، لأن الصعوبة كلها في أن كلا التفسيرين رقم صالح.
قراءة واحد بنظرة
لا تستطيع التحويل في رأسك، لكنك تستطيع فحص المعقولية. الطوابع التي تبدأ بـ17 تقع في منتصف العشرينيات من هذا القرن. أما التي تبدأ بـ16 ففي أوائلها. أما التي تبدأ بـ15 ففي أواخر العقد السابق. كل تغيّر في الخانة الأولى يعادل نحو ثلاث سنوات، وهذا يكفي لتمييز طابع معقول من طابع تالف.
القيمة 0 هي نقطة البداية نفسها، وإليها يؤول التاريخ الغائب كثيرًا. رؤية 1 يناير 1970 في واجهة تعني في الغالب الأعمّ أن حقلًا كان فارغًا، لا أن شيئًا وقع في 1970.
الأرقام السالبة مشروعة وتعدّ إلى الوراء: −86400 هو 31 ديسمبر 1969. ترفضها أنظمة كثيرة مع ذلك، ولهذا كسرت تواريخ الميلاد قبل 1970 استمارات كثيرة جدًّا.
2038
العدد الصحيح ذو الإشارة بـ32 بت يقف عند 2,147,483,647. بوصفه طابع Unix زمنيًّا، ذلك هو 19 يناير 2038، الساعة 03:14:07 بتوقيت UTC، وبعد ثانية واحدة يلتفّ راجعًا إلى ديسمبر 1901.
كل شيء حالي يستعمل 64 بت، وهو ما يدفع الحدّ إلى ما بعد ما تبقّى من عمر الشمس. المشكلة الباقية في أماكن لا يحدّثها أحد: المتحكّمات المدمجة، وصيغ الملفات القديمة التي فيها حقل 32 بت مثبّت في تخطيطها، وقواعد البيانات التي اختير نوع عمودها في 2003.
تسبّبت فعلًا في أعطال حقيقية في أنظمة تحسب تواريخ بعد عقود — فقروض الرهن العقاري لثلاثين سنة بدأت تصطدم بها في 2008.
الثواني الكبيسة، والكذبة في التعريف
دوران الأرض ليس منتظمًا تمامًا، فتُضاف ثوانٍ كبيسة أحيانًا لإبقاء الساعات متوافقة معه. يتجاهلها وقت Unix: فهو معرَّف كأن كل يوم يحوي 86,400 ثانية بالضبط.
إذن وقت Unix ليس عدّ الثواني التي مضت فعلًا. إنه عدّ الأيام مضروبًا، وهذا شيء مختلف اختلافًا دقيقًا، والفرق لا يهمّ إلا إن كنت تقيس زمن شيء يمتدّ عبر ثانية كبيسة — حيث يمكن أن يقع الطابع الزمني نفسه مرّتين.
المكسب هائل وهو سبب هذا الاختيار: تحويل طابع زمني إلى تاريخ حساب خالص، بلا جدول تعديلات تاريخية تعود إليه.
أين تصادف واحدًا
السجلّات وقواعد البيانات، وهي الحالة المعتادة. الترتيب سهل والمقارنة سهلة، وهذا بالضبط سبب استعمال هذه الصيغة.
رموز JWT، حيث دعوى انتهاء الصلاحية طابع Unix زمني بالثواني. الرمز المرفوض لانتهاء صلاحيته يستحقّ غالبًا أن تفكّ ترميزه لترى ما تقوله صلاحيته فعلًا.
رسائل Discord. كتابة <t:1735689600:F> تظهر تاريخًا كاملًا بتوقيت كل قارئ، و:R تظهره «بعد 3 ساعات». هذا أنظف حلّ للجدولة عبر المناطق الزمنية تملكه منصّة محادثة، والحصول على قيمة الثواني هو الجزء المزعج الوحيد.
تصديرات جداول البيانات، وفيها يعضّ التباس الثواني والميلي ثانية عادةً، لأن النظام المصدِّر والنظام المستورد نادرًا ما يتّفقان.
التحويل
محوّل الطوابع الزمنية يعمل في الاتّجاهين، وينبغي أن يذكر أي وحدة قرأ، فهذا موضع الالتباس. الاتّجاه الآخر — من تاريخ إلى طابع — يحتاج منطقة زمنية، لأن التاريخ دونها ليس لحظة.
هذه النقطة الأخيرة توقع الناس: «1 مارس 2025» طابع زمني مختلف في طوكيو وفي لوس أنجلوس. تلك مشكلة قائمة بذاتها.
الخلاصة
ثوانٍ منذ بداية 1970 بتوقيت UTC، مع تجاهل الثواني الكبيسة. عشر خانات تعني ثواني، وثلاث عشرة تعني ميلي ثانية. 1 يناير 1970 في واجهة يعني حقلًا فارغًا. أما العدّاد فينتهي في 19 يناير 2038 لكل ما زال يستعمل 32 بت.