ما التنسيق الذي تُستخدمه الطوابع الزمنية في JSON
الخلاصة: أرقام Epoch وسلاسل ISO لكل منهما مقايضاته، لكن خلطهما هو ما يكسر الأمور فعلًا. استخدم ISO 8601 مع إزاحة، وخزّن UTC، واعرض بتوقيت المستخدم.

الخلاصة: استخدم ISO 8601 بإزاحة صريحة على السلك، وخزّن UTC بـZ في النهاية، وحوّل عند العرض فقط؛ وإن اخترت أرقام Epoch، فثبّت الثواني مقابل الميلي ثانية عالميًا وضع الوحدة في اسم الحقل.
لماذا لا يكفي 2026-10-30 14:30:00
تلك السلسلة لا تحمل منطقة زمنية. 14:30 في شنغهاي و14:30 في لندن يفترقان بثماني ساعات، ولا سبيل لمعرفة المقصود. new Date('2026-10-30 14:30:00') يُحلَّل في المنطقة المحلية لـزمن تشغيل البرنامج، فيستخرج الخادم والمتصفح لحظتين مختلفتين من حمولة واحدة — نوع الخطأ الذي لا يُعاد إنتاجه أبدًا.
و2026-10-30 المجرد ليس لحظة على الإطلاق. صالح لأعياد الميلاد وفترات الفوترة، وخاطئ لوقت الإنشاء.
تنسيقان صالحان
سلاسل ISO 8601
{
"createdAt": "2026-10-30T14:30:00+08:00",
"updatedAt": "2026-10-30T06:30:00Z"
}
مقروءة، وقابلة للترتيب عندما يكون التنسيق متسقًا، بدقة ميلي ثانية عند الحاجة، وواصفة لنفسها.
أرقام Epoch
{ "createdAt": 1793519400 }
مضغوطة وبلا لبس، لكنها غير مقروءة، والثواني مقابل الميلي ثانية خطر دائم. إن اخترت Epoch، فوحّد الوحدة وضعها في اسم الحقل: createdAtMs أكثر أمانًا بكثير من createdAt.
اتفاقيات يستحسن تثبيتها مبكرًا
| العنصر | الاتفاقية |
|---|---|
| تنسيق السلك | ISO 8601 بـZ أو +08:00 |
| منطقة التخزين | UTC، فلا يدخل التوقيت الصيفي في الصورة أبدًا |
| الدقة | الميلي ثانية كافية |
| تسمية الحقول | createdAt، updatedAt، expiresAt |
| التواريخ البحتة | حقل date منفصل، مثل birthday: "1990-01-01" |
| المدد | عدد صحيح مع وحدة، مثل timeoutMs: 3000 |
العرض
new Intl.DateTimeFormat('en-GB', {
dateStyle: 'medium',
timeStyle: 'short',
timeZone: 'Europe/London',
}).format(new Date('2026-10-30T06:30:00Z'));
حدد timeZone صراحةً عندما يجب ألا يتبع العرض الجهاز. الاعتماد على افتراضي المتصفح صحيح للأوقات الموجهة للمستخدم وخاطئ للتقارير.
ثلاثة أخطاء متكررة
التواريخ المجردة تُحلَّل كمنتصف ليل UTC. وفق مواصفة ECMAScript، سلاسل التاريخ فقط UTC بينما سلاسل التاريخ والوقت محلية. هذا التناقض مصدر موثوق لأخطاء يوم واحد.
منطقة قاعدة البيانات تخالف المسلسل. MySQL datetime لا يحمل منطقة؛ اكتب محليًا واقرأ كـUTC فينزاح كل شيء بمقدار الإزاحة.
التوقيت الصيفي. تخزين أوقات محلية مستقبلية يخلق لحظات غير موجودة أو متكررة. وUTC لا يحمل مثل هذه الفجوات.
الأسئلة الشائعة
كيف أختار بين ISO 8601 وأرقام Epoch؟
استخدم ISO 8601 عندما يقرأ البشر الحمولة، أو عندما تريد ترتيبًا معجميًا، أو عندما يجب أن تحمل القيمة منطقتها الزمنية؛ والتكلفة نحو عشرة بايتات إضافية ومكتبة تحليل. واستخدم أرقام Epoch عندما تكون المضغوطة والبساطة عبر اللغات أهم، لكن ثبّت الثواني مقابل الميلي ثانية عالميًا وبيّن أي وحدة يحملها الحقل.
هل يجب أن يتشارك تاريخ مجرد وطابع زمني الحقل نفسه؟
لا. 2026-10-30 المجرد يوم تقويمي بلا وقت وبلا منطقة، بينما يُتوقع من حقل الطابع الزمني أن يحمل لحظة دقيقة. أبقِ أعياد الميلاد وفترات الفوترة في حقل date منفصل، واستخدم حقل ISO 8601 ينتهي بـAt لأوقات الإنشاء أو التحديث.