Temporal की मदद से, इवेंट के बीच के अंतर का हिसाब लगाना और समयावधि को फ़ॉर्मैट करना

वेब सुविधाएं: Temporal Intl.DurationFormat

इवेंट के बीच बीत चुके या बचे हुए समय का हिसाब लगाने के लिए, पहले मैन्युअल तरीके से हिसाब लगाना पड़ता था या बाहरी लाइब्रेरी का इस्तेमाल करना पड़ता था. जैसे, ट्रायल खत्म होने, सदस्यता के काउंटडाउन या एसएलए विंडो के बीच का समय. साथ ही, इस समय को स्थानीय भाषा में और किसी व्यक्ति के लिए आसानी से पढ़े जा सकने वाले फ़ॉर्मैट में दिखाने के लिए भी ऐसा करना पड़ता था. लेगसी Date ऑब्जेक्ट, सिर्फ़ इपॉक मिलीसेकंड को ट्रैक करता है. इससे कैलेंडर-महीने के हिसाब से हिसाब लगाने, डेलाइट सेविंग टाइम (डीएसटी) ट्रांज़िशन, और यूनिट को बैलेंस करने में गड़बड़ी होने की संभावना रहती है.

Temporal एपीआई, Temporal.ZonedDateTime को Temporal.Duration और Intl.DurationFormat के साथ जोड़ता है. इससे डीएसटी के हिसाब से समय के अंतर, कॉन्फ़िगर की जा सकने वाली यूनिट बैलेंसिंग, कैलेंडर के हिसाब से अवधि की तुलना, और स्थानीय भाषा के हिसाब से फ़ॉर्मैटिंग की सुविधा मिलती है.

इन्हें कैसे लागू करें

  1. Temporal.ZonedDateTime एंडपॉइंट पाना: सिस्टम टाइम ज़ोन में मौजूदा समय के लिए Temporal.Now.zonedDateTimeISO() का इस्तेमाल करें. इसके अलावा, अगर टारगेट इवेंट का टाइम ज़ोन, उपयोगकर्ता के सिस्टम के डिफ़ॉल्ट टाइम ज़ोन से अलग है, तो साफ़ तौर पर IANA टाइम ज़ोन स्ट्रिंग—Temporal.Now.zonedDateTimeISO(timeZone)—पास करें.
  2. .since() और .until() की मदद से, अवकलज का हिसाब लगाना:
    • किसी पिछले इवेंट के बाद से बीते समय का हिसाब लगाने के लिए, now.since(start, options) का इस्तेमाल करें.
    • आने वाले समय में होने वाले किसी इवेंट में बचे समय का हिसाब लगाने के लिए, now.until(end, options) का इस्तेमाल करें.
    • largestUnit (जैसे, 'year', 'month', 'day', 'hour') और smallestUnit (जैसे, 'minute') को पास करें, ताकि नतीजे के तौर पर मिलने वाले Temporal.Duration को बैलेंस और राउंड किया जा सके.
  3. अलग-अलग Temporal.Duration ऑब्जेक्ट को बैलेंस करना या उनकी तुलना करना:
    • Temporal.Duration.from({ minutes: 90 }) का इस्तेमाल करके, अलग-अलग समयावधि बनाएं और duration.round({ largestUnit: 'hour' }) का इस्तेमाल करके, यूनिट को फिर से बैलेंस करें. कैलेंडर के महीनों, सालों या डीएसटी ट्रांज़िशन के दौरान बैलेंस करते समय, relativeTo का इस्तेमाल करें.
    • Temporal.Duration.compare(d1, d2, { relativeTo }) का इस्तेमाल करके, दो अवधियों की तुलना करें. अगर किसी अवधि में कैलेंडर यूनिट (years, months, weeks) शामिल हैं या डीएसटी की सीमाएं पार हो रही हैं, तो relativeTo के तौर पर PlainDate या ZonedDateTime पास करना ज़रूरी है.
  4. इंसानों और मशीनों के लिए फ़ॉर्मैट:
    • इस्तेमाल करने वाले लोगों के लिए उपलब्ध स्थानीय भाषा में लिखे गए टेक्स्ट के लिए, duration.toLocaleString(locale, options) का इस्तेमाल करें. यह Intl.DurationFormat को डेलिगेट करता है.
    • duration.toString() का इस्तेमाल सिर्फ़ मशीन से पढ़े जा सकने वाले ISO 8601 ड्यूरेशन स्ट्रिंग (जैसे कि P1M2DT4H) के लिए करें.

उदाहरण: बिना शुल्क के आज़माने की अवधि खत्म होने के बाद, अलग-अलग देशों/इलाकों के हिसाब से कीमत और फ़ॉर्मैटिंग

// 1. Get the current time in an explicit target IANA time zone (or omit the
// argument to use the system's current time zone).
const tz = 'America/New_York';
const now = Temporal.Now.zonedDateTimeISO(tz);

// 2. Combine separate date and time strings directly.
// Do not build an ISO string with template literals; chain Temporal methods instead.
const startDateStr = '2025-01-01';
const startTimeStr = '12:00:00';
const endDateStr = '2025-01-31';
const endTimeStr = '12:00:00';

const start = Temporal.PlainDate.from(startDateStr).toPlainDateTime(startTimeStr).toZonedDateTime(tz);
const end = Temporal.PlainDate.from(endDateStr).toPlainDateTime(endTimeStr).toZonedDateTime(tz);

// 3. Calculate differences using .since() and .until()
// ZonedDateTime differences default to largestUnit: 'hour' (days are not a fixed
// length across DST, so Temporal won't balance into days unless asked). Pass
// largestUnit: 'day' or a calendar unit ('week', 'month', 'year') when you want a
// human-scale breakdown instead of e.g. PT720H. smallestUnit rounds away
// seconds and sub-second noise so the formatted string stays readable.
const timeActive = now.since(start, { largestUnit: 'year', smallestUnit: 'minute' });
const timeRemaining = now.until(end, { largestUnit: 'year', smallestUnit: 'minute' });

// 4. Format durations for display with .toLocaleString() (Intl.DurationFormat)
// instead of manually concatenating unit numbers and suffixes. 'en-US' is used
// here for deterministic output; pass undefined to use the user's locale.
console.log(`Active: ${timeActive.toLocaleString('en-US', { style: 'narrow' })}`);
console.log(`Remaining: ${timeRemaining.toLocaleString('en-US', { style: 'long' })}`);

// Use .toString() for ISO 8601 serialization (e.g., API payloads or <time datetime="...">)
console.log(`ISO 8601: ${timeRemaining.toString()}`);

// 5. Check status via .sign, and compare durations with Temporal.Duration.compare()
const isExpired = timeRemaining.sign < 0;
// Pass relativeTo when comparing durations that may include calendar months/years or DST shifts
const isPastHalfway = Temporal.Duration.compare(timeActive, timeRemaining, { relativeTo: now }) > 0;

उदाहरण: स्टैंडअलोन ड्यूरेशन (round और Intl.DurationFormat) को बैलेंस करना

// Convert a raw unit count (e.g., 90 minutes) into a balanced breakdown (1 hour, 30 minutes)
const rawDuration = Temporal.Duration.from({ minutes: 90 });
const balanced = rawDuration.round({ largestUnit: 'hour' });

// Format via duration.toLocaleString() or directly with Intl.DurationFormat
const formatter = new Intl.DurationFormat('en-US', { style: 'long' });
console.log(formatter.format(balanced)); // "1 hour, 30 minutes"

रणनीति को लागू करने के तरीके और सबसे सही तरीके

  • Temporal.ZonedDateTime का इस्तेमाल, असल दुनिया में होने वाले इवेंट की गणनाओं के लिए करें. ये इवेंट, खास टाइम ज़ोन में होते हैं. जैसे, सदस्यता का रिन्यूअल या इवेंट का काउंटडाउन. साथ ही, सिस्टम के डिफ़ॉल्ट टाइम ज़ोन के अलावा किसी अन्य टाइम ज़ोन के हिसाब से गणना करते समय, Temporal.Now.zonedDateTimeISO(timeZone) को साफ़ तौर पर timeZone पास करें.
  • DO combine separate date and time strings with Temporal methods, e.g. Temporal.PlainDate.from(dateStr).toPlainDateTime(timeStr).toZonedDateTime(tz) or Temporal.PlainDate.from(dateStr).toZonedDateTime({ timeZone: tz, plainTime: timeStr }), instead of interpolating an ISO string like `${dateStr}T${timeStr}`.
  • ज़रूर पास करें largestUnit (जैसे, 'day', 'month', 'year') .since(), .until() या .round() में, जब आपको घंटों से ज़्यादा समय को बैलेंस करना हो; ZonedDateTime अंतर के तरीके डिफ़ॉल्ट रूप से 'hour' पर सेट होते हैं.
  • दो समयावधियों की तुलना करते समय, Temporal.Duration.compare(d1, d2, { relativeTo }) का इस्तेमाल करें. साथ ही, जब भी किसी समयावधि में कैलेंडर यूनिट (months, years) या टाइम ज़ोन के हिसाब से दिन शामिल हों, तो relativeTo ऐंकर दें.
  • क्या करें: उपयोगकर्ता को अवधि दिखाने के लिए, duration.toLocaleString() या new Intl.DurationFormat(locale, { style }) ('long', 'short', 'narrow' या 'digital') का इस्तेमाल करके फ़ॉर्मैट करें. ${duration.years}y ${duration.months}m... को मैन्युअल तरीके से इंटरपोलेट न करें.
  • ज़रूर इस्तेमाल करें duration.toString(), डेटा या जानकारी जो मशीन आसानी से पढ़ सके ISO 8601 ड्यूरेशन स्ट्रिंग (जैसे, PT1H30M) के लिए. इसे कभी भी इस्तेमाल करने वाले लोगों के लिए उपलब्ध कॉपी के तौर पर इस्तेमाल न करें.
  • PlainTime को HH:MM के तौर पर रेंडर करें (उदाहरण के लिए, <input type="time"> के लिए). इसके लिए, स्ट्रिंग .slice(0, 5) के बजाय .toPlainTime().toString({ smallestUnit: 'minute' }) का इस्तेमाल करें.
  • इंस्टेंस में सीधे तौर पर बदलाव न करें; Temporal ऑब्जेक्ट बदले नहीं जा सकते. .add(), .subtract(), .round() या .with() जैसे ऑपरेशन, नया इंस्टेंस दिखाते हैं.
  • डिफ़रेंशियल के लिए, Date / .getTime() अंकगणित का इस्तेमाल न करें. Date में टाइम ज़ोन के हिसाब से कैलेंडर की गणना नहीं की जा सकती. इसमें सिर्फ़ मिलीसेकंड के हिसाब से सटीक जानकारी मिलती है.
  • Temporal.Duration (या Temporal.ZonedDateTime.compare()) की नेटिव .sign प्रॉपर्टी का इस्तेमाल ज़रूर करें. इससे यह पता चलता है कि कोई अवधि, बीते हुए/खत्म हो चुके समय (sign < 0) को दिखाती है या आने वाले समय में शुरू होने वाली अवधि को.

फ़ॉलबैक रणनीति

Temporal के लिए फ़ॉलबैक और ब्राउज़र की सुविधा

ऐसे ब्राउज़र जो अब तक नेटिव Temporal एपीआई के साथ काम नहीं करते हैं उनके लिए, सुविधा की पहचान करने वाले टूल का इस्तेमाल करें और temporal-polyfill (~15 केबी min+gz) को डाइनैमिक तौर पर लोड करें.

ध्यान दें कि temporal-polyfill को इंपोर्ट करने से, Temporal ऑब्जेक्ट अपने-आप ग्लोबल स्कोप को असाइन नहीं होता. अगर आपका कोड globalThis.Temporal पर निर्भर करता है, तो इसे साफ़ तौर पर असाइन करें.

// Check if Temporal is supported natively
(async () => {
  if (typeof Temporal === 'undefined') {
    // Load the polyfill conditionally
    const module = await import('https://esm.sh/temporal-polyfill');
    globalThis.Temporal = module.Temporal;
    // Extend Date.prototype if needed
    Date.prototype.toTemporalInstant = module.toTemporalInstant;
  }
  initializeApp();
})();

Intl.DurationFormat