مقدمة: لماذا الوقت هو الألم
\n\nكل من كتب كودًا في JavaScript ولو مرة واحدة، واجه هذا الألم. تعرض للمستخدم الوقت 12:00، فيكتب: "عندي 14:00، كل شيء معطل". أو تحفظ التاريخ في قاعدة البيانات، وعند التحميل ينزلق ساعة إلى الوراء. هل هذا مألوف؟
\n\nالعمل مع المناطق الزمنية في JavaScript هو الموضوع الذي يؤجله العديد من المطورين "إلى وقت لاحق". وهذا خطأ. لأنه إذا لم تفهمه من البداية، فسيتعين عليك إعادة كتابة نصف التطبيق لاحقًا.
\n\nفي هذه المقالة، سأشرح كيفية العمل بشكل صحيح مع المناطق الزمنية في JS، وسأعرض أمثلة حقيقية للكود، وسأقدم بعض الحيل التي ستوفر لك ساعات من التصحيح. هيا بنا!
\n\nلماذا يعمل JavaScript بشكل غريب مع التواريخ؟
\n\nلنبدأ بالأساسي: كائن Date في JavaScript ليس، بعبارة ملطفة، هدية. فهو يخزن الوقت بالميلي ثانية منذ 1 يناير 1970 UTC. وكل شيء جيد، ولكن:
- \n
getMonth()يُرجع الأشهر من 0 إلى 11 (يناير هو 0، ديسمبر هو 11) \n - الطرق
getHours()،getMinutes()تُرجع الوقت في المنطقة الزمنية المحلية للمستخدم \n - والطرق
getUTCHours()،getUTCMinutes()— في UTC \n
وهنا يبدأ الالتباس. لنفترض أنك تكتب:
\n\nconst now = new Date();\nconsole.log(now.getHours()); // 14 — إذا كان عندك MSK\nconsole.log(now.getUTCHours()); // 11 — UTC\n\nإذا حفظت now في قاعدة البيانات، ثم قمت باسترجاعه على الخادم في منطقة زمنية أخرى، ستحصل على فوضى. لذلك، القاعدة الأولى للعمل مع التواريخ والمناطق الزمنية في JavaScript — احفظ الوقت دائمًا في UTC، وقم بالتحويل على العميل.
Intl.DateTimeFormat: المنقذ المدمج
\n\nكثيرون لا يعلمون، ولكن في JavaScript الحديثة يوجد API مدمج قوي للعمل مع تنسيق التواريخ مع مراعاة المنطقة الزمنية. وهو Intl.DateTimeFormat. يدعم جميع المناطق الزمنية الرئيسية ويستطيع تنسيق التواريخ بشكل جميل.
مثال أساسي
\n\nconst date = new Date('2025-03-15T12:00:00Z');\n\nconst formatter = new Intl.DateTimeFormat('ar-SA', {\n timeZone: 'America/New_York',\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit'\n});\n\nconsole.log(formatter.format(date)); \n// "15 مارس 2025، 08:00" — الوقت في نيويورك\n\nلاحظ: نمرر التاريخ بصيغة UTC (الحرف Z في النهاية)، و Intl.DateTimeFormat يقوم بنفسه بتحويله إلى المنطقة الزمنية المطلوبة. هذا مثالي لعرض الوقت للمستخدمين من مناطق مختلفة.
قائمة جميع المناطق الزمنية
\n\nإذا كنت لا تعرف أي منطقة زمنية تريد تحديدها، يمكنك الحصول على القائمة الكاملة:
\n\nconsole.log(Intl.supportedValuesOf('timeZone'));\n// ["Africa/Abidjan", "Africa/Accra", ..., "Pacific/Wallis"]\n\nتحتوي هذه القائمة على أكثر من 500 منطقة زمنية. استخدمها للتأكد من أن منطقتك الزمنية مدعومة.
\n\nMoment.js: كلاسيكي ولكن مع تحفظات
\n\nلفترة طويلة، كان moment.js هو المعيار للعمل مع التواريخ في JavaScript. فهو يستطيع التحليل، والتنسيق، والتعامل مع التواريخ، وبالطبع العمل مع المناطق الزمنية عبر الإضافة moment-timezone.
التثبيت
\n\nnpm install moment moment-timezone\n\nمثال مع المناطق الزمنية
\n\nconst moment = require('moment-timezone');\n\nconst now = moment();\nconsole.log(now.tz('Europe/Moscow').format('YYYY-MM-DD HH:mm'));\n// 2025-03-15 14:00 — توقيت موسكو\n\nconst nyTime = moment.tz('2025-03-15 12:00', 'America/New_York');\nconsole.log(nyTime.clone().tz('Europe/Moscow').format('YYYY-MM-DD HH:mm'));\n// 2025-03-15 19:00 — الفرق 7 ساعات\n\nهام: moment.js هي مكتبة قديمة (legacy). المؤلفون أنفسهم يوصون بالانتقال