دليل شامل لاستخدام واجهة برمجة تطبيقات Temporal في JavaScript لإجراء حسابات دقيقة وبديهية للفترات الزمنية، يغطي كل شيء من الإنشاء الأساسي للمدة إلى العمليات الحسابية المتقدمة والتنسيق.
المدة الزمنية في JavaScript Temporal: إتقان حسابات الفترات الزمنية
تقدم واجهة برمجة التطبيقات Temporal في JavaScript طريقة حديثة وقوية للتعامل مع التواريخ والأوقات والفترات الزمنية. يمثل كائن Temporal.Duration
مدة زمنية، مما يوفر نهجًا واضحًا وبديهيًا لإجراء العمليات الحسابية على الفترات الزمنية. تتعمق هذه المقالة في تفاصيل Temporal.Duration
، وتوضح كيفية إنشاء المدد الزمنية ومعالجتها وتنسيقها لمختلف حالات الاستخدام.
ما هو Temporal.Duration؟
يمثل Temporal.Duration
فترة زمنية، معبرًا عنها بالسنوات والأشهر والأيام والساعات والدقائق والثواني وأجزاء من الثانية (مللي ثانية، ميكرو ثانية، نانو ثانية). على عكس كائنات Date
التي تمثل نقطة محددة في الزمن، يمثل Temporal.Duration
مقدارًا من الوقت. وهو يلتزم بتنسيق المدة الزمنية ISO 8601 (على سبيل المثال، يمثل P1Y2M10DT2H30M
سنة واحدة وشهرين و 10 أيام وساعتين و 30 دقيقة). تم تصميم واجهة برمجة التطبيقات Temporal لتكون أكثر بديهية وأقل عرضة للخطأ من كائن Date
القديم.
إنشاء كائنات Temporal.Duration
هناك عدة طرق لإنشاء كائنات Temporal.Duration
:
1. من كائن بسيط (Plain Object)
يمكنك إنشاء مدة زمنية عن طريق تمرير كائن بالخصائص المطلوبة:
const duration = new Temporal.Duration(1, 2, 10, 2, 30, 0, 0, 0);
console.log(duration.toString()); // الناتج: P1Y2M10DT2H30M
ينشئ هذا مدة زمنية قدرها سنة واحدة وشهران و 10 أيام وساعتان و 30 دقيقة. لاحظ أن المعاملات تتوافق مع الترتيب التالي: years
, months
, weeks
, days
, hours
, minutes
, seconds
, milliseconds
, microseconds
, nanoseconds
.
2. من سلسلة نصية بصيغة ISO 8601
يمكنك أيضًا إنشاء مدة زمنية من سلسلة نصية بصيغة ISO 8601 باستخدام Temporal.Duration.from()
:
const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
console.log(duration.toString()); // الناتج: P1Y2M10DT2H30M
هذا مفيد بشكل خاص عند التعامل مع المدد الزمنية المخزنة في تنسيق سلسلة نصية أو المستلمة من مصدر خارجي.
3. استخدام دوال add()
و subtract()
مع Temporal.Instant
و Temporal.ZonedDateTime
وغيرها.
عندما تقوم بجمع أو طرح Temporal.Duration
من أنواع Temporal الأخرى (مثل Temporal.Instant
أو Temporal.ZonedDateTime
)، يتم إرجاع Temporal.Duration
يمثل الفرق بين النقطتين الزمنيتين إذا قمت بطرحهما بعد ذلك. على سبيل المثال:
const now = Temporal.Now.zonedDateTimeISO();
const later = now.add({ hours: 5 });
const duration = later.since(now);
console.log(duration.toString()); // الناتج: PT5H
الوصول إلى مكونات المدة الزمنية
يمكنك الوصول إلى المكونات الفردية لكائن Temporal.Duration
باستخدام خصائصه:
const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
console.log(duration.years); // الناتج: 1
console.log(duration.months); // الناتج: 2
console.log(duration.days); // الناتج: 10
console.log(duration.hours); // الناتج: 2
console.log(duration.minutes); // الناتج: 30
console.log(duration.seconds); // الناتج: 0
console.log(duration.milliseconds); // الناتج: 0
console.log(duration.microseconds); // الناتج: 0
console.log(duration.nanoseconds); // الناتج: 0
إجراء العمليات الحسابية على المدد الزمنية
تدعم كائنات Temporal.Duration
الجمع والطرح باستخدام دالتي add()
و subtract()
. تعيد هذه الدوال كائن Temporal.Duration
جديدًا يمثل نتيجة العملية.
const duration1 = Temporal.Duration.from("P1Y2M");
const duration2 = Temporal.Duration.from("P3M4D");
const addedDuration = duration1.add(duration2);
console.log(addedDuration.toString()); // الناتج: P1Y5M4D
const subtractedDuration = duration1.subtract(duration2);
console.log(subtractedDuration.toString()); // الناتج: P10M26D
يمكنك أيضًا ربط هذه الدوال لإجراء حسابات أكثر تعقيدًا:
const duration = Temporal.Duration.from("P1D").add({ hours: 12 }).subtract({ minutes: 30 });
console.log(duration.toString()); // الناتج: P1DT11H30M
تعيد دالة negated()
كائن Temporal.Duration
جديدًا مع عكس إشارة جميع المكونات:
const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
const negatedDuration = duration.negated();
console.log(negatedDuration.toString()); // الناتج: -P1Y2M10DT2H30M
تعيد دالة abs()
كائن Temporal.Duration
جديدًا مع جميع المكونات كقيم موجبة (قيم مطلقة):
const duration = Temporal.Duration.from("-P1Y2M10DT2H30M");
const absoluteDuration = duration.abs();
console.log(absoluteDuration.toString()); // الناتج: P1Y2M10DT2H30M
تسمح لك دالة with()
بإنشاء نسخة Temporal.Duration
جديدة مع تغيير بعض أو كل الخصائص إلى قيم جديدة. إذا لم يتم تحديد قيمة في الكائن المُمرر، فسيتم استخدام القيمة الأصلية للمدة. على سبيل المثال:
const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
const newDuration = duration.with({ years: 2, days: 5 });
console.log(newDuration.toString()); // الناتج: P2Y2M5DT2H30M
تسوية (Normalizing) المدد الزمنية
يمكن أحيانًا التعبير عن المدد الزمنية في شكل غير مسوّى (على سبيل المثال، P1Y12M
، والتي يمكن تبسيطها إلى P2Y
). تحاول دالة normalized()
تبسيط المدة إلى شكلها الأكثر إيجازًا. ومع ذلك، فإنها تتطلب تاريخًا مرجعيًا للتعامل مع تعقيدات أطوال الأشهر المتغيرة. للتسوية بشكل صحيح، ستحتاج إلى نسخة من Temporal.PlainDate
أو Temporal.ZonedDateTime
أو Temporal.Instant
.
على سبيل المثال، تتطلب تسوية مدة زمنية تتضمن أشهرًا وأيامًا تاريخًا مرجعيًا:
const duration = Temporal.Duration.from("P1M32D");
const referenceDate = Temporal.PlainDate.from("2024-01-01");
const normalizedDuration = duration.normalized({ relativeTo: referenceDate });
console.log(normalizedDuration.toString()); // الناتج: P2M1D
في هذا المثال، يتم تسوية المدة P1M32D
بالنسبة إلى 1 يناير 2024، مما ينتج عنه P2M1D
لأن يناير به 31 يومًا.
إذا كنت تتعامل فقط مع مكونات الوقت (ساعات، دقائق، ثواني، إلخ)، يمكنك التسوية بدون تاريخ مرجعي:
const duration = Temporal.Duration.from("PT25H61M");
const normalizedDuration = duration.normalized({ relativeTo: null }); //أو احذف معامل relativeTo
console.log(normalizedDuration.toString()); // الناتج: P1DT2H1M
مقارنة المدد الزمنية
يمكنك مقارنة المدد الزمنية باستخدام دالة compare()
. تعيد هذه الدالة:
- -1 إذا كانت المدة الأولى أقصر من المدة الثانية.
- 0 إذا كانت المدتان متساويتين.
- 1 إذا كانت المدة الأولى أطول من المدة الثانية.
const duration1 = Temporal.Duration.from("P1Y");
const duration2 = Temporal.Duration.from("P6M");
const comparisonResult = Temporal.Duration.compare(duration1, duration2);
console.log(comparisonResult); // الناتج: 1
أمثلة عملية
1. حساب الوقت المتبقي لحدث ما
لنفترض أنك تريد حساب الوقت المتبقي حتى حدث معين. باستخدام Temporal.Now.zonedDateTimeISO()
للحصول على الوقت الحالي، وطرح تاريخ الحدث. إذا كان تاريخ الحدث قد مضى، فسيكون الناتج سالبًا.
const eventDate = Temporal.ZonedDateTime.from({ timeZone: 'America/Los_Angeles', year: 2024, month: 12, day: 25, hour: 9, minute: 0, second: 0 });
const now = Temporal.Now.zonedDateTimeISO('America/Los_Angeles');
const durationUntilEvent = eventDate.since(now);
console.log(durationUntilEvent.toString()); // الناتج: على سبيل المثال، P262DT14H30M (حسب التاريخ والوقت الحاليين)
2. تتبع مدة مهام المشروع
في إدارة المشاريع، يمكنك استخدام Temporal.Duration
لتتبع المدة المقدرة أو الفعلية للمهام.
const task1EstimatedDuration = Temporal.Duration.from("PT8H"); // 8 ساعات
const task2EstimatedDuration = Temporal.Duration.from("PT16H"); // 16 ساعة
const totalEstimatedDuration = task1EstimatedDuration.add(task2EstimatedDuration);
console.log(`إجمالي المدة المقدرة: ${totalEstimatedDuration.toString()}`); // الناتج: إجمالي المدة المقدرة: P1DT
3. حساب العمر
بينما يتطلب حساب العمر بدقة مراعاة السنوات الكبيسة والمناطق الزمنية، يمكن أن يوفر Temporal.Duration
تقديرًا معقولاً:
const birthDate = Temporal.PlainDate.from("1990-05-15");
const currentDate = Temporal.PlainDate.from("2024-01-20");
const ageDuration = currentDate.since(birthDate, { smallestUnit: 'years' });
console.log(`العمر التقديري: ${ageDuration.years} سنوات`); // الناتج: العمر التقديري: 33 سنوات
4. عرض المدد الزمنية بصيغة قابلة للقراءة البشرية
غالبًا ما تحتاج إلى عرض المدد الزمنية بتنسيق يمكن للبشر قراءته. على الرغم من أن Temporal.Duration
لا يحتوي على دوال تنسيق مدمجة، يمكنك إنشاء منطق تنسيق مخصص:
function formatDuration(duration) {
const parts = [];
if (duration.years) parts.push(`${duration.years} ${duration.years > 1 ? 'سنوات' : 'سنة'}`);
if (duration.months) parts.push(`${duration.months} ${duration.months > 1 ? 'أشهر' : 'شهر'}`);
if (duration.days) parts.push(`${duration.days} ${duration.days > 1 ? 'أيام' : 'يوم'}`);
if (duration.hours) parts.push(`${duration.hours} ${duration.hours > 1 ? 'ساعات' : 'ساعة'}`);
if (duration.minutes) parts.push(`${duration.minutes} ${duration.minutes > 1 ? 'دقائق' : 'دقيقة'}`);
if (duration.seconds) parts.push(`${duration.seconds} ${duration.seconds > 1 ? 'ثوان' : 'ثانية'}`);
return parts.join('، ');
}
const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
const formattedDuration = formatDuration(duration);
console.log(formattedDuration); // الناتج: سنة واحدة، شهران، 10 أيام، ساعتان، 30 دقيقة
استخدامات متقدمة واعتبارات
1. التعامل مع المناطق الزمنية
عند التعامل مع فترات زمنية تعبر حدود المناطق الزمنية أو انتقالات التوقيت الصيفي، من الضروري استخدام Temporal.ZonedDateTime
لضمان دقة الحسابات. استخدام Temporal.PlainDate
و Temporal.PlainTime
سيتجنب أي تحويلات للمناطق الزمنية.
2. أصغر وحدة وتقريب الأرقام
غالبًا ما تقبل دالتا `since()` و `until()` خيارات لتحديد أصغر وحدة للمدة الناتجة. على سبيل المثال، حساب الوقت *حتى* حدث ما وحصر النتائج بالأيام.
const eventDate = Temporal.PlainDate.from("2024-12-25");
const now = Temporal.PlainDate.from("2024-01-20");
const durationUntilEvent = now.until(eventDate, { smallestUnit: 'days' });
console.log(durationUntilEvent.toString()); //مثال للناتج PT340D
3. الثواني الكبيسة
لا يأخذ Temporal في الحسبان الثواني الكبيسة بشكل أساسي. إذا كنت تحتاج إلى دقة قصوى، فستحتاج إلى التعامل مع الثواني الكبيسة بشكل منفصل.
4. مناطق IANA الزمنية
تعتمد واجهة برمجة التطبيقات Temporal على قاعدة بيانات المناطق الزمنية التابعة لـ IANA (هيئة أرقام الإنترنت المخصصة). تأكد من أن بيئتك تحتوي على إصدار محدث من قاعدة بيانات IANA للتعامل بدقة مع تحويلات المناطق الزمنية.
أفضل الممارسات
- استخدم تنسيق ISO 8601 للسلاسل النصية للمدة: هذا يضمن الاتساق وقابلية التشغيل البيني.
- اختر نوع Temporal المناسب: استخدم
Temporal.PlainDate
,Temporal.PlainTime
,Temporal.ZonedDateTime
, أوTemporal.Instant
بناءً على ما إذا كنت بحاجة إلى دعم المنطقة الزمنية أم لا. - قم بتسوية المدد عند الضرورة: تبسط التسوية المدد وتجعل مقارنتها أسهل.
- تعامل مع المناطق الزمنية بعناية: يمكن أن تكون تحويلات المناطق الزمنية معقدة، لذا استخدم
Temporal.ZonedDateTime
وكن على دراية بانتقالات التوقيت الصيفي. - ضع في اعتبارك أصغر وحدة: عند حساب المدد، حدد أصغر وحدة للحصول على مستوى الدقة المطلوب.
- اكتب اختبارات الوحدة: اختبر شفرتك المصدرية بدقة لضمان دقة حسابات المدة.
الأخطاء الشائعة
- تجاهل المناطق الزمنية: يمكن أن يؤدي عدم مراعاة المناطق الزمنية إلى حسابات مدة غير صحيحة، خاصة عند التعامل مع الأحداث في مواقع مختلفة.
- استخدام كائن Date القديم: يُعرف كائن
Date
القديم بخصوصياته وتناقضاته. فضل استخدام واجهة برمجة التطبيقات Temporal لمعالجة أكثر موثوقية للتاريخ والوقت. - عدم تسوية المدد: عدم تسوية المدد يمكن أن يجعل المقارنات والحسابات أكثر تعقيدًا.
- تنسيق ISO 8601 غير صحيح: يمكن أن يتسبب استخدام سلسلة نصية لمدة ISO 8601 غير صالحة في حدوث أخطاء.
حالات استخدام واقعية عبر ثقافات مختلفة
يمكن أن تكون واجهة برمجة التطبيقات Temporal مفيدة بشكل خاص في التطبيقات العالمية حيث تكون اختلافات المناطق الزمنية والفروق الثقافية الدقيقة كبيرة. إليك بعض الأمثلة:
- جدولة الأحداث العالمية: جدولة الأحداث بدقة عبر مناطق زمنية متعددة، مع مراعاة انتقالات التوقيت الصيفي. على سبيل المثال، جدولة ندوة عبر الإنترنت تبدأ في الساعة 9:00 صباحًا بتوقيت المحيط الهادئ وعرض وقت البدء المقابل في مناطق زمنية مختلفة مثل توقيت وسط أوروبا (CET) وتوقيت اليابان القياسي (JST) وتوقيت شرق أستراليا (AEDT).
- تخطيط السفر الدولي: حساب مدد السفر، بما في ذلك فترات التوقف وتغييرات المناطق الزمنية. هذا مفيد لإنشاء مسارات الرحلات وإدارة جداول الرحلات الجوية. على سبيل المثال، حساب إجمالي وقت السفر من نيويورك إلى طوكيو، بما في ذلك فترة توقف في لندن والتكيف مع اختلافات المناطق الزمنية.
- التجارة الإلكترونية العالمية: عرض أوقات التسليم المقدرة في المنطقة الزمنية المحلية للمستخدم. يتطلب هذا مراعاة المنطقة الزمنية للمنشأ، ومدة الشحن، والمنطقة الزمنية للوجهة. على سبيل المثال، سلعة يتم شحنها من مستودع في ألمانيا إلى عميل في أستراليا، مع وقت تسليم تقديري يبلغ 7 أيام، يتم عرضه بالتوقيت المحلي للعميل.
- المعاملات المالية عبر الحدود: حساب تراكم الفائدة أو آجال الدفع بدقة عبر مناطق مختلفة. غالبًا ما يتضمن هذا مراعاة أيام العمل والعطلات المختلفة في كل بلد. على سبيل المثال، حساب الفائدة المتراكمة على قرض في سنغافورة، مع مراعاة العطلات الرسمية في سنغافورة.
- تطبيقات التقويم متعددة الثقافات: دعم أنظمة التقويم المختلفة، مثل التقويم الهجري أو العبري، وحساب مدد الأحداث والتذكيرات بدقة بناءً على هذه التقاويم.
- إدارة المشاريع العالمية: تتبع مدد مهام المشروع والمواعيد النهائية عبر فرق موزعة، مع مراعاة جداول العمل المختلفة والمناطق الزمنية.
الخاتمة
يوفر Temporal.Duration
طريقة قوية وبديهية للعمل مع الفترات الزمنية في JavaScript. من خلال فهم ميزاته وأفضل الممارسات، يمكنك بثقة إجراء حسابات مدة دقيقة وموثوقة في تطبيقاتك. يؤدي تبني واجهة برمجة التطبيقات Temporal إلى شفرة أنظف وأكثر قابلية للصيانة ويقلل من مخاطر الأخطاء المرتبطة بمعالجة التاريخ والوقت القديمة.
بينما تتعمق أكثر في واجهة برمجة التطبيقات Temporal، تذكر الرجوع إلى الوثائق الرسمية وتجربة سيناريوهات مختلفة لفهم قدراتها بالكامل. بفضل تصميمه الحديث وميزاته الشاملة، من المقرر أن يُحدث Temporal ثورة في طريقة تعاملنا مع التواريخ والأوقات والمدد في JavaScript.