FlowingDev

شرح توقيت Epoch: الساعة التي تتحرك للأمام فقط

تعلم ما هو توقيت يونكس (أو توقيت Epoch): عدد الثواني التي انقضت منذ 1 يناير 1970، والذي تستخدمه أجهزة الكمبيوتر لتتبع الوقت عالميًا.

جرّب الأداة: محول العصر

في جملة واحدة

توقيت Epoch هو طريقة الكمبيوتر لتتبع الوقت كرقم واحد متزايد باستمرار: إجمالي عدد الثواني التي مرت منذ منتصف ليل 1 يناير 1970 بتوقيت UTC.

المشكلة التي يحلها

البشر والزمن علاقتهم معقدة. عندنا مناطق زمنية، توقيت صيفي، وتنسيقات مثل MM/DD/YYYY مقابل DD/MM/YYYY. نكتب "8 أكتوبر 2024 الساعة 3:00 مساءً"، لكن هذا يعني شيئًا مختلفًا في طوكيو عن تورنتو. إنها فوضى من الغموض.

أجهزة الكمبيوتر، على النقيض تمامًا، تكره الغموض. تحتاج إلى طريقة واحدة، عالمية، وبسيطة رياضيًا لتمثيل لحظة زمنية. محاولة إجراء عمليات حسابية على "8 أكتوبر" كابوس. لكن إجراء عمليات حسابية على رقم عادي؟ هذا هو ما صُنعت أجهزة الكمبيوتر من أجله.

هذه هي المشكلة التي صُمم توقيت يونكس (Unix time) - والذي يسمى أيضًا توقيت Epoch أو توقيت POSIX - لحلها. في الأيام الأولى لنظام التشغيل يونكس في السبعينيات، احتاج مبتكروه إلى نظام بسيط لحفظ الوقت. قرروا اختيار نقطة بداية عشوائية - "epoch" أو "حقبة" - وببساطة... بدأوا العد.

الـ "epoch" المختارة كانت 00:00:00 UTC, January 1, 1970. لماذا هذا التاريخ بالذات؟ كان رقمًا لطيفًا ومستديرًا، وحديثًا بما يكفي لتقنية ذلك الوقت.

منذ تلك اللحظة، كل ثانية تمر تزيد من عداد عالمي. لذا، بدلاً من أن يضطر الكمبيوتر إلى تحليل "الساعة 3:00 مساءً يوم 8 أكتوبر 2024، في تورنتو (وهو توقيت EDT)"، يمكنه ببساطة تخزين الرقم 1728409200. هذا الرقم يمثل تلك اللحظة المحددة في الزمن، في كل مكان على وجه الأرض، في وقت واحد. لا مناطق زمنية، لا تنسيقات، لا "هل هو صباحًا أم مساءً؟". مجرد رقم. حُلّت المشكلة.

كيف يعمل تحت الغطاء

في جوهره، المفهوم بسيط جدًا. ولكن مثل كل شيء في عالم التقنية، الشيطان يكمن في التفاصيل.

الـ Epoch والوحدة

النظام بأكمله مبني على فكرتين:

  1. نقطة البداية (Epoch): هذه ثابتة عند 1970-01-01T00:00:00Z. الحرف Z يرمز إلى Zulu، وهو مصطلح عسكري وجوي لـ UTC (التوقيت العالمي المنسق). في عالم توقيت Epoch، هذه اللحظة هي ببساطة 0.
  2. وحدة القياس: الوحدة القياسية والرسمية هي الثانية.

لذا، الطابع الزمني 1 يمثل 1970-01-01T00:00:01Z. الطابع الزمني لبداية اليوم التالي، 1970-01-02T00:00:00Z، هو 86400 (لأن هناك 60 ثانية * 60 دقيقة * 24 ساعة = 86,400 ثانية في اليوم).

// A date far in the future
const humanDate = new Date('2035-10-26T10:00:00Z');

// Its corresponding Epoch timestamp in seconds
const epochTimestamp = 2071754400;

عندما يعرض لك جهاز الكمبيوتر هذا الطابع الزمني كتوقيت محلي، فإنه يقوم بعملية تحويل خلف الكواليس. يأخذ طابع UTC الزمني العالمي ويطبق فارق المنطقة الزمنية لنظامك لعرضه بطريقة منطقية لك. لكن الرقم الأساسي يظل نقيًا وعالميًا.

الاختلافات: ميلي ثانية، مايكرو ثانية، نانو ثانية

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

الوحدة قيمة مثال (لنفس اللحظة) عدد الأرقام الشائع حالة الاستخدام النموذجية
ثوانٍ 1728409200 10 معيار POSIX؛ واجهات برمجة التطبيقات (APIs)، قواعد البيانات.
ميلي ثانية 1728409200123 13 JavaScript (Date.now())، واجهات برمجة التطبيقات الحديثة.
مايكرو ثانية 1728409200123456 16 أنظمة عالية الأداء، بعض قواعد البيانات.
نانو ثانية 1728409200123456789 19 الحوسبة العلمية، لغة Go.

هذا هو المصدر الأول للأخطاء البرمجية (bugs) عند التعامل مع الطوابع الزمنية. إذا أعطاك نظام ما رقمًا مكونًا من 13 خانة وتعاملت معه على أنه ثوانٍ، فأنت تحاول حساب تاريخ بعد آلاف السنين في المستقبل. تحقق دائمًا من التوثيق (docs) أو انظر إلى عدد الخانات لتعرف ما الذي تتعامل معه.

"مشكلة عام 2038"

هذه قصة كلاسيكية من تراث الكمبيوتر. العديد من الأنظمة القديمة، لتوفير الذاكرة الثمينة، كانت تخزن طابع Epoch الزمني كـ عدد صحيح 32-بت ذي إشارة (32-bit signed integer).

الـ "bit" هو 1 أو 0. "32-bit" تعني أن لديك 32 خانة للآحاد والأصفار. "ذو إشارة" (Signed) تعني أن إحدى هذه الخانات تُستخدم لتحديد ما إذا كان الرقم موجبًا أم سالبًا. هذا يترك 31 خانة للرقم نفسه، والتي يمكن أن تمثل قيمة قصوى تبلغ 2^31 - 1، أو 2,147,483,647.

ماذا يحدث عندما يصل عدد الثواني منذ عام 1970 إلى هذا الحد؟ سيحدث ذلك يوم الثلاثاء، 19 يناير 2038، الساعة 03:14:07 بتوقيت UTC. في الثانية التالية مباشرة، سيحدث overflow للعدد الصحيح. مثل عداد المسافات في السيارة الذي ينقلب من 999999 إلى 000000، سيلتف طابع 32-بت الزمني ليعود إلى أقصى قيمة سالبة له (-2,147,483,648). وهذا يوافق تاريخًا في ديسمبر 1901.

بالنسبة لأي نظام 32-بت لم يتم تحديثه، سيؤدي هذا إلى فوضى زمنية. فكر في الأنظمة المدمجة في السيارات القديمة، أو المعدات الصناعية، أو موجهات الشبكة.

الحل؟ استخدم عدد صحيح 64-بت (64-bit integer). يمكن لعدد صحيح 64-بت تخزين رقم كبير لدرجة مذهلة لن يحدث له overflow لمدة 292 مليار سنة تقريبًا. بحلول ذلك الوقت، ستكون الشمس قد تمددت وابتلعت الأرض منذ زمن طويل، لذا يمكننا اعتباره حلاً دائمًا. معظم أنظمة التشغيل واللغات الحديثة قد قامت بالفعل بالتحويل.

الثواني الكبيسة: تفصيلة مزعجة

دوران الأرض ليس منتظمًا تمامًا؛ إنه يتباطأ بشكل طفيف. للحفاظ على تزامن ساعاتنا الذرية (وهي منتظمة للغاية) مع اليوم الشمسي، تضيف الهيئات الدولية أحيانًا "ثانية كبيسة" إلى التقويم. هذا يعني أن الدقيقة قد تحتوي على 61 ثانية (على سبيل المثال، 23:59:60).

فكيف يتعامل توقيت Epoch مع هذا؟ الإجابة: لا يتعامل معها.

رسميًا، معيار POSIX يتجاهل الثواني الكبيسة. يفترض أن كل يوم يحتوي على 86,400 ثانية بالضبط. عندما تحدث ثانية كبيسة، تتعامل الأنظمة معها بعدة طرق، لكن إحدى الطرق الشائعة هي تكرار الثانية السابقة فعليًا. قد يحدث الطابع الزمني لـ 23:59:59 مرتين. هذا يحافظ على العد المستمر وغير المنقطع للثواني ولكنه يعني أن طابع يونكس الزمني لا يتوافق دائمًا بشكل مثالي مع توقيت UTC في العالم الحقيقي. بالنسبة لـ 99.9% من التطبيقات، هذه ليست مشكلة. بالنسبة للتداول عالي التردد أو القياسات العلمية، هذه مشكلة كبيرة.

قصص من الواقع

قضية الـ Cache المسافر عبر الزمن

كان فريق من المطورين يطلق ميزة جديدة مدعومة بنظام تخزين مؤقت (caching). لتحسين الأداء، كانوا يخزنون البيانات مؤقتًا لمدة ساعة واحدة. كان المنطق بسيطًا: expiration_time = current_time() + 3600. قاموا بنشر الكود عبر مجموعة خوادمهم.

فجأة، بدأت تظهر أخطاء غريبة. كانت البيانات تختفي من الـ cache على الفور تقريبًا. بعد ساعات من البحث المحموم عن الأخطاء، وجدوا السبب. أحد الخوادم الجديدة في المجموعة كانت ساعة نظامه مضبوطة بشكل غير صحيح - كانت متأخرة بخمس دقائق عن جميع الخوادم الأخرى.

عندما يصل طلب مستخدم إلى خادم صحيح، فإنه سيخزن البيانات في الـ cache مع وقت انتهاء صلاحية، على سبيل المثال، 1678886400 (12:00 ظهرًا). إذا وصل طلب لاحق لنفس البيانات إلى الخادم "البطيء"، فإن ساعته تشير إلى 11:55 صباحًا. عندما يفحص الـ cache، يرى وقت انتهاء صلاحية 12:00 ظهرًا ويخدم البيانات بشكل صحيح. ولكن إذا وصل الطلب الأول إلى الخادم البطيء، فسيحدد وقت انتهاء صلاحية 1678882800 (11:00 صباحًا، وقته الخاص، زائد ساعة واحدة وهو 12:00 ظهرًا). لكن الوقت كان 11:55 صباحًا. انتظر، هذا ليس صحيحًا.

لنجرب مرة أخرى. وقت الخادم A هو 12:00. يحدد انتهاء صلاحية الـ cache لـ 12:00 + ساعة واحدة = 13:00. ساعة الخادم B بطيئة؛ يعتقد أنها 11:55. عندما يحتاج الخادم B للكتابة في الـ cache، فإنه يحدد انتهاء الصلاحية 11:55 + ساعة واحدة = 12:55. الآن، إذا رأى الخادم A عنصرًا ينتهي في 12:55، فسيعتقد أن أمامه 55 دقيقة متبقية، بينما يعتقد الخادم B أن أمامه ساعة كاملة. هذا يؤدي إلى عدم تناسق.

الفوضى الحقيقية تبدأ عندما تكون الساعات غير متزامنة بشكل كبير. إذا كانت ساعة الخادم B متأخرة بساعة (يعتقد أنها 11:00 بينما هي 12:00)، فسيحدد وقت انتهاء صلاحية 11:00 + ساعة واحدة = 12:00. من منظور الخادم A، ينتهي عنصر الـ cache الجديد هذا في نفس الثانية التي تم إنشاؤه فيها. البيانات تختفي فعليًا.

الدرس المستفاد: طوابع يونكس الزمنية مطلقة، لكنها تُولَّد من ساعات النظام التي قد لا تكون كذلك. في الأنظمة الموزعة (distributed systems)، الحفاظ على تزامن الساعات (عادةً باستخدام بروتوكول وقت الشبكة، أو NTP) ليس مجرد ممارسة جيدة؛ بل هو أمر حاسم.

الـ API الذي كان يتحدث بالميلي ثانية

كان مطور واجهة أمامية (frontend) يبني لوحة تحكم لعرض نشاط المستخدم. قدمت واجهة برمجة التطبيقات الخلفية (backend API) حقل last_login مع طابع زمني، مثل 1678886400. استخدم المطور مكتبة JavaScript لعرض هذا: new Date(1678886400).

كانت النتيجة غريبة. كان آخر تسجيل دخول لكل مستخدم يُعرض على أنه "20 يناير 1970". ماذا كان يحدث؟

أمضى المطور ساعة يلوم المكتبة، وكوده، ومراحل القمر. أخيرًا، حاول دمج نقطة نهاية (endpoint) مختلفة من نفس الـ API. هذه المرة، كان الطابع الزمني 1678886400123. كان يحتوي على 13 رقمًا! فجأة، فهم الأمر. كائن Date في JavaScript يتوقع طابعًا زمنيًا بـ الميلي ثانية، وليس بالثواني.

كان الـ backend يرسل طابعًا زمنيًا قياسيًا من 10 أرقام بالثواني. وكان الـ frontend يفسر 1,678,886,400 على أنه عدد الميلي ثانية منذ الـ epoch، وهو تاريخ يقع بعد أسابيع قليلة فقط من بدء الـ epoch في عام 1970. كان الإصلاح بسيطًا: new Date(1678886400 * 1000).

الدرس المستفاد: دائمًا، دائمًا، دائمًا تحقق من دقة الطابع الزمني. فرق ثلاثة أصفار هو الفرق بين اليوم وعام 1970.

أخطاء وفخاخ شائعة

  • نسيان المنطقة الزمنية. طوابع يونكس الزمنية دائمًا، بدون استثناء، بتوقيت UTC. عند تحويل أحدها إلى تاريخ يمكن للبشر قراءته، ستستخدم لغة البرمجة أو الأداة التي تستخدمها دائمًا المنطقة الزمنية المحلية لجهاز الكمبيوتر الخاص بك. يمكن أن يسبب هذا ارتباكًا هائلاً إذا لم تأخذه في الحسبان. 1728409200 هي لحظة زمنية واحدة محددة، لكنها ستظهر كـ 06:00 في نيويورك و 19:00 في طوكيو. الرقم هو الحقيقة؛ العرض هو تفسير.

  • الخلط بين الثواني والميلي ثانية. هذا هو خطأ "off-by-1000" الكلاسيكي. إنه الخطأ الأكثر شيوعًا عند التعامل مع الطوابع الزمنية. كقاعدة عامة: 10 أرقام تعني ثوانٍ، 13 رقمًا تعني ميلي ثانية. إذا رأيت شيئًا آخر، فكن متشككًا جدًا.

  • تجاهل مشكلة 2038. إذا كنت تبني تطبيق ويب قياسيًا بلغة حديثة، فمن المحتمل أن تكون بخير. ولكن إذا كنت تكتب كود C لجهاز IoT مدمج، أو نظام معلومات وترفيه في سيارة، أو تقوم بصيانة نظام 32-بت قديم، فإن مشكلة Y2038 هي قنبلة موقوتة حقيقية جدًا.

  • استخدام نصوص غامضة لإنشاء طوابع زمنية. إنشاء طابع زمني من نص مثل "March 15, 2025 10:00 PM" هو دعوة للمشاكل. هل هذا في منطقتك الزمنية المحلية؟ منطقة الخادم الزمنية؟ UTC؟ قم دائمًا بإنشاء طوابع زمنية من كائنات مدركة للمنطقة الزمنية أو استخدم نصوص UTC صريحة (مثل صيغة ISO 8601: 2025-03-15T22:00:00Z).

لماذا يجب أن يكون على رادارك

ببساطة لا يمكنك أن تكون مطورًا عصريًا ولا تفهم توقيت Epoch. إنها اللغة المشتركة (lingua franca) للوقت في عالم الحوسبة. ستواجهه في كل مكان:

  • واجهات برمجة التطبيقات (APIs): حمولات JSON تستخدمه باستمرار لحقول مثل createdAt و updatedAt و expires_at.
  • توكنات JWT: الادعاءات exp (انتهاء الصلاحية)، iat (صدر في)، و nbf (ليس قبل) كلها طوابع زمنية يونكس قياسية.
  • قواعد البيانات: غالبًا ما يكون تخزين الوقت كرقم صحيح واحد أكثر كفاءة للفهرسة والتخزين من استخدام نوع DATETIME المعقد.
  • ملفات السجلات (Log Files): استخدام الطوابع الزمنية الرقمية يجعل من السهل جدًا ربط الأحداث عبر العشرات من الخوادم والخدمات المختلفة، حتى لو كانت في مناطق زمنية مختلفة.
  • أنظمة الملفات: معظم أنظمة الملفات تخزن تواريخ إنشاء وتعديل الملفات كطوابع زمنية ليونكس.

فهم كيفية عمله يتيح لك تصحيح فئة كاملة من الأخطاء الصعبة المتعلقة بالوقت بثقة. إنه يسمح لك باختراق عالم البشر الفوضوي المليء بالمناطق الزمنية والتقاويم والتفكير في الوقت بالطريقة التي يفكر بها الكمبيوتر: كخط بسيط ومنظم من الأرقام.

تعمق أكثر

انتهينا من النظرية. حان وقت التطبيق — 100% في متصفحك.

جرّب الأداة: محول العصر