العربية

دليل شامل لاستخدام واجهة برمجة تطبيقات 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(). تعيد هذه الدالة:

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 للتعامل بدقة مع تحويلات المناطق الزمنية.

أفضل الممارسات

الأخطاء الشائعة

حالات استخدام واقعية عبر ثقافات مختلفة

يمكن أن تكون واجهة برمجة التطبيقات Temporal مفيدة بشكل خاص في التطبيقات العالمية حيث تكون اختلافات المناطق الزمنية والفروق الثقافية الدقيقة كبيرة. إليك بعض الأمثلة:

الخاتمة

يوفر Temporal.Duration طريقة قوية وبديهية للعمل مع الفترات الزمنية في JavaScript. من خلال فهم ميزاته وأفضل الممارسات، يمكنك بثقة إجراء حسابات مدة دقيقة وموثوقة في تطبيقاتك. يؤدي تبني واجهة برمجة التطبيقات Temporal إلى شفرة أنظف وأكثر قابلية للصيانة ويقلل من مخاطر الأخطاء المرتبطة بمعالجة التاريخ والوقت القديمة.

بينما تتعمق أكثر في واجهة برمجة التطبيقات Temporal، تذكر الرجوع إلى الوثائق الرسمية وتجربة سيناريوهات مختلفة لفهم قدراتها بالكامل. بفضل تصميمه الحديث وميزاته الشاملة، من المقرر أن يُحدث Temporal ثورة في طريقة تعاملنا مع التواريخ والأوقات والمدد في JavaScript.

المدة الزمنية في JavaScript Temporal: إتقان حسابات الفترات الزمنية | MLOG