دليل معمق لواجهة Temporal API في JavaScript، الحل الحديث للتعامل مع التواريخ والأوقات بفعالية في سياقات دولية متنوعة.
واجهة Temporal API في JavaScript: التعامل الحديث مع التاريخ والوقت لجمهور عالمي
لطالما كان كائن `Date` في JavaScript مصدر إحباط للمطورين. أدت قابليته للتغيير، وواجهة برمجة التطبيقات غير المتسقة، ودعمه الضعيف للمناطق الزمنية إلى ظهور العديد من المكتبات مثل Moment.js و date-fns لسد هذه الثغرات. الآن، مع واجهة Temporal API، تقدم JavaScript حلاً حديثًا ومدمجًا للتعامل مع التواريخ والأوقات بوضوح ودقة محسّنين. تقدم هذه المقالة نظرة شاملة على واجهة Temporal API، مع التركيز على ميزاتها وفوائدها واستخدامها في سياقات دولية متنوعة.
ما هي واجهة Temporal API؟
واجهة Temporal API هي كائن عالمي جديد في JavaScript مصمم لمعالجة أوجه القصور في كائن `Date`. إنها توفر واجهة برمجة تطبيقات نظيفة وغير قابلة للتغيير للعمل مع التواريخ والأوقات والمناطق الزمنية وأنظمة التقويم. والأهم من ذلك، أنها تهدف إلى تمثيل مفاهيم التاريخ والوقت بطريقة تتوافق بشكل أوثق مع الاستخدام والتوقعات في العالم الحقيقي، مما يجعل التدويل أكثر سهولة.
الميزات الرئيسية:
- عدم القابلية للتغيير (Immutability): كائنات Temporal غير قابلة للتغيير، مما يعني أن العمليات مثل إضافة أيام أو أشهر تُرجع كائنات جديدة بدلاً من تعديل الكائن الأصلي. هذا يزيل مصدرًا شائعًا للأخطاء ويجعل الكود أسهل في الفهم.
- واجهة برمجة تطبيقات واضحة: توفر Temporal واجهة برمجة تطبيقات متسقة وبديهية لعمليات التاريخ والوقت الشائعة.
- دعم المناطق الزمنية: تتضمن Temporal دعمًا قويًا للمناطق الزمنية، مما يتيح لك العمل مع التواريخ والأوقات في مواقع مختلفة دون تعقيدات كائن `Date` القديم. تستخدم قاعدة بيانات المناطق الزمنية IANA، مما يضمن معلومات دقيقة ومحدثة.
- أنظمة التقويم: بالإضافة إلى التقويم الغريغوري، تدعم Temporal أنظمة تقويم بديلة، لتلبية احتياجات الثقافات والمناطق المتنوعة.
- دقة محسّنة: توفر Temporal دقة تصل إلى النانوثانية، مما يعالج قيود كائن `Date` الذي يعتمد على الميلي ثانية.
كائنات Temporal الأساسية
تقدم واجهة Temporal API عدة أنواع جديدة من الكائنات. فيما يلي بعض الأنواع الأساسية:
- `Temporal.PlainDate`: يمثل تاريخًا (سنة، شهر، يوم) بدون منطقة زمنية.
- `Temporal.PlainTime`: يمثل وقتًا (ساعة، دقيقة، ثانية، ميلي ثانية، ميكروثانية، نانوثانية) بدون تاريخ أو منطقة زمنية.
- `Temporal.PlainDateTime`: يمثل تاريخًا ووقتًا بدون منطقة زمنية.
- `Temporal.ZonedDateTime`: يمثل تاريخًا ووقتًا مع منطقة زمنية محددة.
- `Temporal.Instant`: يمثل لحظة زمنية محددة، مقاسة بالنانوثانية منذ حقبة يونكس (1 يناير 1970 بالتوقيت العالمي المنسق).
- `Temporal.TimeZone`: يمثل منطقة زمنية.
- `Temporal.Duration`: يمثل فترة زمنية (على سبيل المثال، ساعتان و 30 دقيقة).
- `Temporal.YearMonth`: يمثل سنة وشهرًا.
- `Temporal.MonthDay`: يمثل شهرًا ويومًا.
العمل مع التواريخ
إنشاء `Temporal.PlainDate`
لإنشاء `Temporal.PlainDate`، يمكنك استخدام المُنشئ:
const plainDate = new Temporal.PlainDate(2024, 10, 27); // Year, Month (1-12), Day
console.log(plainDate.toString()); // Output: 2024-10-27
يمكنك أيضًا استخدام التابع `from`، الذي يقبل سلسلة نصية بتنسيق ISO 8601:
const plainDateFromString = Temporal.PlainDate.from('2024-10-27');
console.log(plainDateFromString.toString()); // Output: 2024-10-27
الحصول على مكونات التاريخ
يمكنك الوصول إلى مكونات التاريخ الفردية باستخدام خصائص مثل `year` و `month` و `day`:
console.log(plainDate.year); // Output: 2024
console.log(plainDate.month); // Output: 10
console.log(plainDate.day); // Output: 27
العمليات الحسابية على التاريخ
لإضافة أو طرح أيام أو أسابيع أو أشهر أو سنوات، استخدم التابعين `plus` و `minus`. تُرجع هذه التوابع كائن `Temporal.PlainDate` جديدًا:
const nextWeek = plainDate.plus({ days: 7 });
console.log(nextWeek.toString()); // Output: 2024-11-03
const lastMonth = plainDate.minus({ months: 1 });
console.log(lastMonth.toString()); // Output: 2024-09-27
مقارنة التواريخ
يمكنك مقارنة التواريخ باستخدام التابع `compare`:
const date1 = new Temporal.PlainDate(2024, 10, 27);
const date2 = new Temporal.PlainDate(2024, 11, 15);
console.log(Temporal.PlainDate.compare(date1, date2)); // Output: -1 (date1 is earlier than date2)
العمل مع الأوقات
إنشاء `Temporal.PlainTime`
لإنشاء `Temporal.PlainTime`، استخدم المُنشئ:
const plainTime = new Temporal.PlainTime(10, 30, 0); // Hour, Minute, Second
console.log(plainTime.toString()); // Output: 10:30:00
أو استخدم التابع `from` مع سلسلة نصية للوقت بتنسيق ISO 8601:
const plainTimeFromString = Temporal.PlainTime.from('10:30:00');
console.log(plainTimeFromString.toString()); // Output: 10:30:00
الحصول على مكونات الوقت
console.log(plainTime.hour); // Output: 10
console.log(plainTime.minute); // Output: 30
console.log(plainTime.second); // Output: 0
العمليات الحسابية على الوقت
const later = plainTime.plus({ minutes: 15 });
console.log(later.toString()); // Output: 10:45:00
العمل مع التاريخ والوقت معًا
إنشاء `Temporal.PlainDateTime`
يمكنك إنشاء `Temporal.PlainDateTime` مباشرة أو عن طريق دمج `Temporal.PlainDate` و `Temporal.PlainTime`:
const plainDateTime = new Temporal.PlainDateTime(2024, 10, 27, 10, 30, 0);
console.log(plainDateTime.toString()); // Output: 2024-10-27T10:30:00
const date = new Temporal.PlainDate(2024, 10, 27);
const time = new Temporal.PlainTime(10, 30, 0);
const combinedDateTime = date.toPlainDateTime(time);
console.log(combinedDateTime.toString()); // Output: 2024-10-27T10:30:00
المناطق الزمنية
التعامل مع المناطق الزمنية بشكل صحيح أمر بالغ الأهمية للتطبيقات التي تتعامل مع مستخدمين في مواقع مختلفة. توفر واجهة Temporal API دعمًا قويًا للمناطق الزمنية من خلال كائني `Temporal.ZonedDateTime` و `Temporal.TimeZone`.
إنشاء `Temporal.ZonedDateTime`
لإنشاء `Temporal.ZonedDateTime`، تحتاج إلى `Temporal.PlainDateTime` ومعرّف منطقة زمنية. تعتمد معرّفات المناطق الزمنية على قاعدة بيانات المناطق الزمنية IANA (على سبيل المثال، `America/Los_Angeles`، `Europe/London`، `Asia/Tokyo`).
const plainDateTime = new Temporal.PlainDateTime(2024, 10, 27, 10, 30, 0);
const timeZone = 'America/Los_Angeles';
const zonedDateTime = plainDateTime.toZonedDateTime(timeZone);
console.log(zonedDateTime.toString()); // Output: 2024-10-27T10:30:00-07:00[America/Los_Angeles] (The offset will depend on DST rules)
بدلاً من ذلك، يمكنك إنشاء `Temporal.ZonedDateTime` من `Instant`.
const instant = Temporal.Instant.fromEpochSeconds(1666866600); // Example timestamp
const zonedDateTimeFromInstant = instant.toZonedDateTimeISO(timeZone); // Timezone like 'America/Los_Angeles'
console.log(zonedDateTimeFromInstant.toString());
التحويل بين المناطق الزمنية
يمكنك تحويل `Temporal.ZonedDateTime` إلى منطقة زمنية مختلفة باستخدام التابع `withTimeZone`:
const newTimeZone = 'Europe/London';
const zonedDateTimeInLondon = zonedDateTime.withTimeZone(newTimeZone);
console.log(zonedDateTimeInLondon.toString()); // Output: 2024-10-27T18:30:00+01:00[Europe/London]
العمل مع فروق التوقيت
يوفر التابع `getOffsetStringFor` للكائن `Temporal.TimeZone` السلسلة النصية للفرق الزمني لـ `Temporal.Instant` معين:
const timeZoneObject = new Temporal.TimeZone(timeZone);
const offsetString = timeZoneObject.getOffsetStringFor(zonedDateTime.toInstant());
console.log(offsetString); // Output: -07:00 (Depending on DST rules)
من الضروري استخدام معرّفات المناطق الزمنية الصحيحة من IANA للحصول على حسابات دقيقة. يتم الحفاظ على هذه المعرّفات وتحديثها بانتظام لتعكس التغييرات في التوقيت الصيفي وحدود المناطق الزمنية.
الفترات الزمنية (Durations)
يمثل كائن `Temporal.Duration` فترة زمنية. يمكن استخدامه للإضافة إلى أو الطرح من التواريخ والأوقات.
إنشاء `Temporal.Duration`
يمكنك إنشاء `Temporal.Duration` باستخدام المُنشئ، مع تحديد السنوات والأشهر والأيام والساعات والدقائق والثواني والميلي ثانية والميكروثانية والنانوثانية:
const duration = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 8, 9); // Years, Months, Days, Hours, Minutes, Seconds, Milliseconds, Microseconds, Nanoseconds
console.log(duration.toString()); // Output: P1Y2M3DT4H5M6.007008009S
أو باستخدام سلسلة نصية للفترة الزمنية بتنسيق ISO 8601:
const durationFromString = Temporal.Duration.from('P1Y2M3DT4H5M6S');
console.log(durationFromString.toString()); // Output: P1Y2M3DT4H5M6S
إضافة الفترات الزمنية إلى التواريخ والأوقات
const plainDate = new Temporal.PlainDate(2024, 10, 27);
const duration = new Temporal.Duration(0, 0, 7); // 7 days
const newDate = plainDate.plus(duration);
console.log(newDate.toString()); // Output: 2024-11-03
لاحظ أن إضافة الفترات الزمنية التي تتضمن أشهرًا أو سنوات إلى التواريخ تتطلب دراسة متأنية، حيث يمكن أن يختلف عدد الأيام في الشهر أو السنة.
أنظمة التقويم
تدعم واجهة Temporal API أنظمة تقويم مختلفة بالإضافة إلى التقويم الغريغوري. هذا أمر بالغ الأهمية للتطبيقات التي تحتاج إلى التعامل مع التواريخ في سياقات ثقافية متنوعة. بينما لا يزال الدعم في طور التطور، فإنه يوفر أساسًا للتوسع في المستقبل.
استخدام التقاويم البديلة
لاستخدام تقويم معين، يمكنك تحديده عند إنشاء كائنات Temporal:
const hebrewDate = new Temporal.PlainDate(5785, 1, 1, { calendar: 'hebrew' });
console.log(hebrewDate.toString()); // The specific output may vary depending on the implementation and formatting. Requires polyfill in many environments as of writing this.
مهم: قد يتطلب دعم التقاويم غير الغريغورية استخدام polyfills أو دعمًا محددًا من المتصفح/البيئة. تحقق من وثائق Temporal API وجداول توافق المتصفحات للحصول على أحدث المعلومات.
تنسيق التواريخ والأوقات
بينما تركز واجهة Temporal API على معالجة التاريخ والوقت، يتم التعامل مع التنسيق عادةً بواسطة كائن `Intl.DateTimeFormat`، وهو جزء من واجهة برمجة تطبيقات التدويل. تعمل كائنات Temporal بسلاسة مع `Intl.DateTimeFormat`.
استخدام `Intl.DateTimeFormat`
إليك كيفية تنسيق `Temporal.PlainDate` باستخدام `Intl.DateTimeFormat`:
const plainDate = new Temporal.PlainDate(2024, 10, 27);
const formatter = new Intl.DateTimeFormat('en-US', { year: 'numeric', month: 'long', day: 'numeric' });
console.log(formatter.format(plainDate)); // Output: October 27, 2024
const formatterGerman = new Intl.DateTimeFormat('de-DE', { year: 'numeric', month: 'long', day: 'numeric' });
console.log(formatterGerman.format(plainDate)); // Output: 27. Oktober 2024
يمكنك تخصيص خيارات التنسيق لتناسب احتياجاتك. الوسيط الأول لـ `Intl.DateTimeFormat` هو الإعدادات المحلية (locale)، التي تحدد اللغة والاصطلاحات الإقليمية المستخدمة للتنسيق. استخدام إعدادات محلية مختلفة (مثل 'en-US' و 'de-DE' و 'fr-FR' و 'ja-JP') ينتج تنسيقات إخراج مختلفة.
تنسيق `Temporal.ZonedDateTime`
تنسيق `Temporal.ZonedDateTime` مشابه، ولكن يمكنك أيضًا تضمين معلومات المنطقة الزمنية في الإخراج:
const plainDateTime = new Temporal.PlainDateTime(2024, 10, 27, 10, 30, 0);
const timeZone = 'America/Los_Angeles';
const zonedDateTime = plainDateTime.toZonedDateTime(timeZone);
const formatter = new Intl.DateTimeFormat('en-US', { year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric', timeZoneName: 'short' });
console.log(formatter.format(zonedDateTime)); // Output: October 27, 2024, 10:30 AM PDT (The time zone abbreviation depends on DST rules)
أفضل الممارسات للتدويل
عند العمل مع التواريخ والأوقات في سياق عالمي، ضع في اعتبارك أفضل الممارسات التالية:
- استخدم معرّفات المناطق الزمنية IANA: استخدم دائمًا معرّفات المناطق الزمنية IANA (مثل `America/Los_Angeles` و `Europe/London`) للتعامل الدقيق مع المناطق الزمنية.
- كن على دراية بالتوقيت الصيفي: يمكن أن يؤثر التوقيت الصيفي (DST) على فروق التوقيت. تتعامل واجهة Temporal API تلقائيًا مع انتقالات التوقيت الصيفي.
- استخدم `Intl.DateTimeFormat` للتنسيق: استخدم كائن `Intl.DateTimeFormat` لتنسيق التواريخ والأوقات وفقًا لإعدادات المستخدم المحلية.
- ضع في اعتبارك أنظمة التقويم: إذا كان تطبيقك يحتاج إلى دعم مستخدمين في سياقات ثقافية مختلفة، ففكر في استخدام أنظمة تقويم بديلة.
- خزّن التواريخ والأوقات بالتوقيت العالمي المنسق (UTC): عند تخزين التواريخ والأوقات في قاعدة بيانات، من الأفضل تخزينها بالتوقيت العالمي المنسق لتجنب مشاكل المناطق الزمنية. ثم قم بتحويلها إلى التوقيت المحلي لأغراض العرض. توفر Temporal توابع للتحويل من وإلى التوقيت العالمي المنسق.
- اختبر بشكل شامل: اختبر تطبيقك بمناطق زمنية وإعدادات محلية وأنظمة تقويم مختلفة للتأكد من أنه يعمل بشكل صحيح لجميع المستخدمين.
مقارنة واجهة Temporal API بكائن Date القديم
فيما يلي جدول يسلط الضوء على الاختلافات والمزايا الرئيسية لواجهة Temporal API مقارنة بكائن `Date` القديم:
الميزة | كائن `Date` القديم | واجهة Temporal API |
---|---|---|
القابلية للتغيير | قابل للتغيير (يعدّل الكائن الأصلي) | غير قابل للتغيير (يُرجع كائنات جديدة) |
دعم المناطق الزمنية | محدود وغالبًا ما يسبب مشاكل | قوي ودقيق، يعتمد على قاعدة بيانات المناطق الزمنية IANA |
واجهة برمجة التطبيقات | غير متسقة وصعبة الاستخدام | واضحة ومتسقة وبديهية |
الدقة | ميلي ثانية | نانوثانية |
أنظمة التقويم | يقتصر على التقويم الغريغوري | يدعم أنظمة تقويم بديلة (مع دعم متطور) |
التدويل | يتطلب مكتبات خارجية للتدويل القوي | دعم مدمج وتكامل سلس مع `Intl.DateTimeFormat` |
دعم المتصفحات و Polyfills
باعتبارها واجهة برمجة تطبيقات جديدة نسبيًا، لا يزال دعم المتصفحات لواجهة Temporal API في طور التطور. تحقق من أحدث جداول توافق المتصفحات (على سبيل المثال، على MDN Web Docs) لمعرفة المتصفحات والبيئات التي تدعمها أصلاً. بالنسبة للمتصفحات أو البيئات الأقدم التي لا تدعمها أصلاً، يمكنك استخدام polyfills لتوفير وظائف واجهة Temporal API. ابحث عن "Temporal API polyfill" على الويب للعثور على الخيارات المناسبة.
الخاتمة
تمثل واجهة Temporal API في JavaScript خطوة كبيرة إلى الأمام في التعامل مع التواريخ والأوقات في JavaScript. إن عدم قابليتها للتغيير، وواجهة برمجة التطبيقات الواضحة، ودعمها القوي للمناطق الزمنية، وقدرات أنظمة التقويم تجعلها أداة قوية للمطورين الذين يبنون تطبيقات تحتاج إلى العمل مع التواريخ والأوقات بدقة وموثوقية في سياقات دولية متنوعة. بينما لا يزال دعم المتصفحات في طور التطور، فإن فوائد واجهة Temporal API تجعلها تستحق التعلم والاعتماد في المشاريع الجديدة. من خلال تبني واجهة Temporal API واتباع أفضل ممارسات التدويل، يمكنك إنشاء تطبيقات توفر تجربة تاريخ ووقت سلسة ودقيقة للمستخدمين في جميع أنحاء العالم.