كيفية تنسيق التواريخ في مناطق زمنية مختلفة

عرض التواريخ والأوقات لأي منطقة زمنية باستخدام واجهة برمجة التطبيقات Intl.DateTimeFormat في جافا سكريبت

مقدمة

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

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

توفر واجهة برمجة التطبيقات Intl.DateTimeFormat في جافا سكريبت خيار timeZone لتنسيق التواريخ والأوقات لأي منطقة زمنية. يشرح هذا الدرس سبب وجود المناطق الزمنية، وكيفية تعامل جافا سكريبت معها داخليًا، وكيفية تنسيق التواريخ بشكل صحيح للمستخدمين في أي مكان في العالم.

لماذا توجد المناطق الزمنية

تدور الأرض، مما يخلق النهار والليل في مواقع مختلفة في أوقات مختلفة. عندما تكون الشمس فوق نيويورك، تكون قد غربت بالفعل في لندن ولم تشرق بعد في طوكيو. تختبر كل منطقة وقت الظهيرة في لحظة مختلفة.

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

لكل منطقة زمنية انحراف قياسي عن التوقيت العالمي المنسق، المختصر UTC. تستخدم نيويورك UTC-5 أو UTC-4 اعتمادًا على التوقيت الصيفي. تستخدم لندن UTC+0 أو UTC+1. تستخدم طوكيو UTC+9 على مدار العام.

عندما تعرض الأوقات للمستخدمين، تحتاج إلى التحويل من اللحظة العالمية إلى وقت الساعة المحلية الذي يتوقعون رؤيته.

كيف يخزن جافاسكريبت الأوقات داخليًا

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

const date = new Date('2025-03-15T20:00:00Z');
console.log(date.getTime());
// Output: 1742331600000

الحرف Z في نهاية سلسلة ISO يشير إلى توقيت UTC. يخزن كائن التاريخ الطابع الزمني 1742331600000، الذي يمثل نفس اللحظة للجميع في العالم، بغض النظر عن منطقتهم الزمنية.

عندما تستدعي طرقًا مثل toString() على كائن التاريخ، يقوم جافاسكريبت بتحويل الطابع الزمني UTC إلى المنطقة الزمنية المحلية للعرض. يمكن أن يؤدي هذا التحويل التلقائي إلى حدوث ارتباك عندما ترغب في عرض الأوقات لمنطقة زمنية مختلفة.

توفر واجهة برمجة التطبيقات Intl.DateTimeFormat مع خيار timeZone تحكمًا صريحًا في المنطقة الزمنية التي يجب استخدامها للتنسيق.

استخدام خيار timeZone

يحدد خيار timeZone المنطقة الزمنية التي يجب استخدامها عند تنسيق التاريخ. قم بتمرير الخيار كجزء من كائن الخيارات عند إنشاء المنسق.

const date = new Date('2025-03-15T20:00:00Z');

const formatter = new Intl.DateTimeFormat('en-US', {
  timeZone: 'America/New_York',
  dateStyle: 'short',
  timeStyle: 'short'
});

console.log(formatter.format(date));
// Output: "3/15/25, 3:00 PM"

يمثل التاريخ الساعة 8:00 مساءً بتوقيت UTC. نيويورك هي UTC-5 خلال التوقيت القياسي أو UTC-4 خلال التوقيت الصيفي. في مارس، يكون التوقيت الصيفي نشطًا، لذا تكون نيويورك UTC-4. يحول المنسق الساعة 8:00 مساءً بتوقيت UTC إلى الساعة 4:00 مساءً بالتوقيت المحلي، لكن المثال يظهر الساعة 3:00 مساءً، مما يشير إلى أن هذا خلال التوقيت القياسي في هذا السيناريو المحدد.

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

فهم أسماء المناطق الزمنية IANA

يقبل خيار timeZone معرفات المناطق الزمنية من قاعدة بيانات المناطق الزمنية IANA. تستخدم هذه المعرفات تنسيق المنطقة/المدينة، مثل America/New_York أو Europe/London أو Asia/Tokyo.

const date = new Date('2025-03-15T20:00:00Z');

const zones = [
  'America/New_York',
  'Europe/London',
  'Asia/Tokyo',
  'Australia/Sydney'
];

zones.forEach(zone => {
  const formatter = new Intl.DateTimeFormat('en-US', {
    timeZone: zone,
    dateStyle: 'short',
    timeStyle: 'long'
  });

  console.log(`${zone}: ${formatter.format(date)}`);
});

// Output:
// America/New_York: 3/15/25, 4:00:00 PM EDT
// Europe/London: 3/15/25, 8:00:00 PM GMT
// Asia/Tokyo: 3/16/25, 5:00:00 AM JST
// Australia/Sydney: 3/16/25, 7:00:00 AM AEDT

تُظهر كل منطقة زمنية وقتًا محليًا مختلفًا لنفس اللحظة. تُظهر نيويورك الساعة 4:00 مساءً في 15 مارس. تُظهر لندن الساعة 8:00 مساءً في 15 مارس. أما طوكيو وسيدني فقد تقدمتا بالفعل إلى 16 مارس، وتُظهران الساعة 5:00 صباحًا و 7:00 صباحًا على التوالي.

تتعامل أسماء IANA مع التوقيت الصيفي تلقائيًا. يعرف المنسق أن America/New_York يتبدل بين التوقيت الشرقي القياسي والتوقيت الصيفي الشرقي ويطبق الإزاحة الصحيحة لأي تاريخ.

العثور على أسماء المناطق الزمنية IANA الصالحة

تحتوي قاعدة بيانات IANA على عدة مئات من معرفات المناطق الزمنية. تتضمن الأنماط الشائعة:

  • America/New_York لمدينة نيويورك
  • America/Los_Angeles للوس أنجلوس
  • America/Chicago لشيكاغو
  • Europe/London للندن
  • Europe/Paris لباريس
  • Europe/Berlin لبرلين
  • Asia/Tokyo لطوكيو
  • Asia/Shanghai لشنغهاي
  • Asia/Kolkata للهند
  • Australia/Sydney لسيدني
  • Pacific/Auckland لأوكلاند

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

يمكنك البحث عن القائمة الكاملة للمعرفات في وثائق قاعدة بيانات المناطق الزمنية IANA.

استخدام UTC كمنطقة زمنية

المعرّف الخاص UTC يقوم بتنسيق التواريخ في التوقيت العالمي المنسق، والذي ليس له أي إزاحة عن خط الطول الرئيسي.

const date = new Date('2025-03-15T20:00:00Z');

const formatter = new Intl.DateTimeFormat('en-US', {
  timeZone: 'UTC',
  dateStyle: 'short',
  timeStyle: 'long'
});

console.log(formatter.format(date));
// Output: "3/15/25, 8:00:00 PM UTC"

يتطابق توقيت UTC مع الطابع الزمني الداخلي المخزن في كائن Date. يعد استخدام UTC للتنسيق مفيدًا عند عرض الأوقات التي لا ينبغي أن تتغير بناءً على موقع المستخدم، مثل سجلات الخادم أو الطوابع الزمنية لقاعدة البيانات.

الحصول على المنطقة الزمنية للمستخدم

تُرجع طريقة resolvedOptions() الخيارات الفعلية المستخدمة بواسطة المنسق، بما في ذلك المنطقة الزمنية. عندما تقوم بإنشاء منسق دون تحديد timeZone، فإنه يستخدم افتراضيًا المنطقة الزمنية لنظام المستخدم.

const formatter = new Intl.DateTimeFormat();
const options = formatter.resolvedOptions();

console.log(options.timeZone);
// Output: "America/New_York" (or user's actual time zone)

هذا يعطيك معرّف IANA للمنطقة الزمنية الحالية للمستخدم. يمكنك استخدام هذا المعرّف لتنسيق تواريخ أخرى في نفس المنطقة أو لتخزين تفضيل المنطقة الزمنية للمستخدم.

const userTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;

const formatter = new Intl.DateTimeFormat('en-US', {
  timeZone: userTimeZone,
  dateStyle: 'full',
  timeStyle: 'long'
});

const date = new Date('2025-03-15T20:00:00Z');
console.log(formatter.format(date));
// Output varies based on user's time zone

يضمن هذا النمط عرض التواريخ بالتوقيت المحلي للمستخدم تلقائيًا.

تنسيق نفس اللحظة لمناطق زمنية متعددة

يمكنك تنسيق نفس كائن Date لمناطق زمنية متعددة لإظهار المستخدمين وقت حدوث حدث في مواقع مختلفة.

const meetingTime = new Date('2025-03-15T20:00:00Z');

const zones = [
  { name: 'New York', zone: 'America/New_York' },
  { name: 'London', zone: 'Europe/London' },
  { name: 'Tokyo', zone: 'Asia/Tokyo' }
];

zones.forEach(({ name, zone }) => {
  const formatter = new Intl.DateTimeFormat('en-US', {
    timeZone: zone,
    dateStyle: 'long',
    timeStyle: 'short'
  });

  console.log(`${name}: ${formatter.format(meetingTime)}`);
});

// Output:
// New York: March 15, 2025 at 4:00 PM
// London: March 15, 2025 at 8:00 PM
// Tokyo: March 16, 2025 at 5:00 AM

هذا يساعد المستخدمين على فهم وقت حدوث اجتماع أو حدث في منطقتهم الزمنية وفي المناطق الزمنية للمشاركين الآخرين.

تنسيق التواريخ بدون أوقات عبر المناطق الزمنية

عند تنسيق التواريخ بدون أوقات، يمكن أن تؤثر المنطقة الزمنية على التاريخ التقويمي الذي يظهر. فالتاريخ عند منتصف الليل بتوقيت UTC يقع في تواريخ تقويمية مختلفة في مناطق زمنية مختلفة.

const date = new Date('2025-03-16T01:00:00Z');

const formatter1 = new Intl.DateTimeFormat('en-US', {
  timeZone: 'America/Los_Angeles',
  dateStyle: 'long'
});

const formatter2 = new Intl.DateTimeFormat('en-US', {
  timeZone: 'Asia/Tokyo',
  dateStyle: 'long'
});

console.log(`Los Angeles: ${formatter1.format(date)}`);
console.log(`Tokyo: ${formatter2.format(date)}`);

// Output:
// Los Angeles: March 15, 2025
// Tokyo: March 16, 2025

اللحظة الساعة 1:00 صباحًا بتوقيت UTC في 16 مارس تتوافق مع الساعة 5:00 مساءً في 15 مارس في لوس أنجلوس والساعة 10:00 صباحًا في 16 مارس في طوكيو. يختلف التاريخ التقويمي بيوم واحد بين المنطقتين الزمنيتين.

هذا مهم عند عرض تواريخ للأحداث المجدولة أو المواعيد النهائية أو أي تاريخ يفسره المستخدمون بالنسبة إلى تقويمهم المحلي.

استخدام فروق المناطق الزمنية

بدلاً من معرفات IANA، يمكنك استخدام سلاسل الفروق مثل +01:00 أو -05:00. هذه تمثل فروقًا ثابتة من توقيت UTC.

const date = new Date('2025-03-15T20:00:00Z');

const formatter = new Intl.DateTimeFormat('en-US', {
  timeZone: '+09:00',
  dateStyle: 'short',
  timeStyle: 'long'
});

console.log(formatter.format(date));
// Output: "3/16/25, 5:00:00 AM GMT+9"

تعمل سلاسل الفروق عندما تعرف الفرق الدقيق ولكن ليس الموقع المحدد. ومع ذلك، فهي لا تتعامل مع التوقيت الصيفي. إذا استخدمت -05:00 لتمثيل نيويورك، ستكون الأوقات خاطئة خلال التوقيت الصيفي عندما تستخدم نيويورك فعليًا -04:00.

يُفضل استخدام معرفات IANA لأنها تتعامل مع التوقيت الصيفي تلقائيًا.

فهم كيفية عمل التوقيت الصيفي

تغير العديد من المناطق توقيتها مرتين سنويًا للتوفير في استخدام ضوء النهار. خلال الربيع، تتقدم الساعات ساعة واحدة. وخلال الخريف، تتأخر الساعات ساعة واحدة. هذا يعني أن فارق التوقيت عن UTC للموقع يتغير على مدار العام.

عند استخدام معرفات المناطق الزمنية IANA، تطبق واجهة برمجة التطبيقات Intl.DateTimeFormat تلقائيًا الفارق الزمني الصحيح لأي تاريخ.

const winterDate = new Date('2025-01-15T20:00:00Z');
const summerDate = new Date('2025-07-15T20:00:00Z');

const formatter = new Intl.DateTimeFormat('en-US', {
  timeZone: 'America/New_York',
  dateStyle: 'long',
  timeStyle: 'long'
});

console.log(`Winter: ${formatter.format(winterDate)}`);
console.log(`Summer: ${formatter.format(summerDate)}`);

// Output:
// Winter: January 15, 2025 at 3:00:00 PM EST
// Summer: July 15, 2025 at 4:00:00 PM EDT

في يناير، تستخدم نيويورك التوقيت الشرقي القياسي بفارق UTC-5، وتظهر الساعة 3:00 مساءً. في يوليو، تستخدم نيويورك توقيت شرق الولايات المتحدة الصيفي بفارق UTC-4، وتظهر الساعة 4:00 مساءً. ينتج عن نفس توقيت UTC أوقات محلية مختلفة بناءً على ما إذا كان التوفير في استخدام ضوء النهار نشطًا أم لا.

لا تحتاج إلى تتبع التواريخ التي تستخدم أي فارق زمني. تتعامل واجهة برمجة التطبيقات مع هذا تلقائيًا.

تنسيق الأوقات لجدولة الفعاليات

عند عرض أوقات الفعاليات، قم بتنسيق الوقت في موقع الفعالية واختياريًا في موقع المستخدم.

const eventTime = new Date('2025-03-15T18:00:00Z');
const eventTimeZone = 'Europe/Paris';
const userTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;

const eventFormatter = new Intl.DateTimeFormat('en-US', {
  timeZone: eventTimeZone,
  dateStyle: 'full',
  timeStyle: 'short'
});

const userFormatter = new Intl.DateTimeFormat('en-US', {
  timeZone: userTimeZone,
  dateStyle: 'full',
  timeStyle: 'short'
});

console.log(`Event time: ${eventFormatter.format(eventTime)} (Paris)`);
console.log(`Your time: ${userFormatter.format(eventTime)}`);

// Output (for a user in New York):
// Event time: Saturday, March 15, 2025 at 7:00 PM (Paris)
// Your time: Saturday, March 15, 2025 at 2:00 PM

يوضح هذا النمط للمستخدمين وقت حدوث الفعالية في منطقتها الزمنية الخاصة ومتى يجب عليهم الانضمام بناءً على موقعهم.

تنسيق طوابع الوقت الخاصة بالخادم في المنطقة الزمنية للمستخدم

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

const serverTimestamp = new Date('2025-03-15T20:00:00Z');
const userTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;

const formatter = new Intl.DateTimeFormat(navigator.language, {
  timeZone: userTimeZone,
  dateStyle: 'short',
  timeStyle: 'medium'
});

console.log(`Activity: ${formatter.format(serverTimestamp)}`);
// تختلف المخرجات بناءً على المنطقة الزمنية للمستخدم واللغة المحلية
// بالنسبة لـ en-US في نيويورك: "Activity: 3/15/25, 4:00:00 PM"

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

دمج timeZone مع خيارات أخرى

يعمل خيار timeZone مع جميع خيارات Intl.DateTimeFormat الأخرى. يمكنك تحديد مكونات التاريخ والوقت الفردية، أو استخدام إعدادات النمط المسبقة، أو التحكم في نظام التقويم.

const date = new Date('2025-03-15T20:00:00Z');

const formatter = new Intl.DateTimeFormat('en-US', {
  timeZone: 'Asia/Tokyo',
  weekday: 'long',
  year: 'numeric',
  month: 'long',
  day: 'numeric',
  hour: 'numeric',
  minute: 'numeric',
  second: 'numeric',
  timeZoneName: 'long'
});

console.log(formatter.format(date));
// المخرجات: "Monday, March 16, 2025 at 5:00:00 AM Japan Standard Time"

يتحكم خيار timeZoneName في كيفية ظهور اسم المنطقة الزمنية في المخرجات. ستغطي الدروس اللاحقة هذا الخيار بالتفصيل.

ما يجب تجنبه

لا تستخدم اختصارات المناطق الزمنية مثل EST أو PST أو GMT كقيم لخيار timeZone. هذه الاختصارات غامضة وغير مدعومة بشكل متسق.

// غير صحيح - قد لا تعمل الاختصارات
const formatter = new Intl.DateTimeFormat('en-US', {
  timeZone: 'EST',  // قد يؤدي هذا إلى خطأ
  dateStyle: 'short',
  timeStyle: 'short'
});

استخدم دائمًا معرفات IANA مثل America/New_York أو سلاسل الإزاحة مثل -05:00.

لا تفترض أن المنطقة الزمنية للمستخدم تتطابق مع المنطقة الزمنية للخادم. قم دائمًا بتنسيق الأوقات بشكل صريح في المنطقة الصحيحة أو استخدم المنطقة الزمنية المكتشفة للمستخدم.

إعادة استخدام أدوات التنسيق عبر المناطق الزمنية

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

const dates = [
  new Date('2025-03-15T20:00:00Z'),
  new Date('2025-03-16T14:00:00Z'),
  new Date('2025-03-17T09:00:00Z')
];

const formatter = new Intl.DateTimeFormat('en-US', {
  timeZone: 'Europe/Berlin',
  dateStyle: 'short',
  timeStyle: 'short'
});

dates.forEach(date => {
  console.log(formatter.format(date));
});

// Output:
// "3/15/25, 9:00 PM"
// "3/16/25, 3:00 PM"
// "3/17/25, 10:00 AM"

إنشاء أداة تنسيق يتضمن معالجة الخيارات وتحميل بيانات اللغة المحلية. إعادة استخدام نفس أداة التنسيق لتواريخ متعددة يتجنب هذه العمليات الإضافية.