ইভেন্টের (যেমন, ট্রায়ালের মেয়াদ শেষ হওয়া, সাবস্ক্রিপশনের কাউন্টডাউন বা SLA উইন্ডো) মধ্যে অতিবাহিত বা বাকি থাকা সময় গণনা করা এবং সেই সময়সীমা স্থানীয়, মানুষের-পঠনযোগ্য ফর্ম্যাটে উপস্থাপন করার জন্য ঐতিহাসিকভাবে ম্যানুয়াল গণিত বা এক্সটার্নাল লাইব্রেরির প্রয়োজন হয়। পুরনো Date অবজেক্ট শুধুমাত্র ইপক মিলিসেকেন্ড ট্র্যাক করে, যার ফলে ক্যালেন্ডার-মাস পাটিগণিত, ডেলাইট সেভিং টাইম (DST) ট্রানজিশন এবং ইউনিট ব্যালেন্সিংয়ে ভুল হওয়ার সম্ভাবনা থাকে।
Temporal API, Temporal.ZonedDateTime-এর সাথে Temporal.Duration ও Intl.DurationFormat-কে পেয়ার করে যাতে DST-নিরাপদ সময়ের পার্থক্য, কনফিগার করা যায় এমন ইউনিট ব্যালেন্সিং, ক্যালেন্ডার-সচেতন সময়সীমার তুলনা ও লোকালাইজ করা ফর্ম্যাটিং প্রদান করা যায়।
কীভাবে প্রয়োগ করতে হয়
Temporal.ZonedDateTimeএন্ডপয়েন্ট পান: সিস্টেম টাইম জোনে বর্তমান সময়ের জন্যTemporal.Now.zonedDateTimeISO()ব্যবহার করুন অথবা টার্গেট ইভেন্টের টাইম জোন ব্যবহারকারীর সিস্টেম ডিফল্ট থেকে আলাদা হলে, একটি স্পষ্ট IANA টাইম জোন স্ট্রিং—Temporal.Now.zonedDateTimeISO(timeZone)—পাস করুন।.since()ও.until()-এর সাথে ডিফারেনশিয়াল গণনা করুন:- কোনও পুরনো ইভেন্ট থেকে কত সময় অতিবাহিত হয়েছে তা গণনা করতে
now.since(start, options)ব্যবহার করুন। - ভবিষ্যতের কোনও ইভেন্ট পর্যন্ত বাকি সময় গণনা করতে
now.until(end, options)ব্যবহার করুন। Temporal.Duration-এর ফলাফল ব্যালেন্স ও রাউন্ড করতেlargestUnit(যেমন,'year','month','day','hour') এবংsmallestUnit(যেমন,'minute') পাস করুন।
- কোনও পুরনো ইভেন্ট থেকে কত সময় অতিবাহিত হয়েছে তা গণনা করতে
- ব্যালেন্স বা স্বতন্ত্র
Temporal.Durationঅবজেক্টের তুলনা করুন:Temporal.Duration.from({ minutes: 90 })-এর সাহায্যে স্ট্যান্ডঅ্যালোন সময়সীমা তৈরি করুন এবংduration.round({ largestUnit: 'hour' })-এর সাহায্যে ইউনিট রিব্যালেন্স করুন (ক্যালেন্ডার মাস, বছর বা DST ট্রানজিশন জুড়ে ব্যালেন্স করার সময়relativeToপ্রদান করে)।Temporal.Duration.compare(d1, d2, { relativeTo })-এর সাথে দুটি সময়সীমা তুলনা করুন—যেকোনও সময়সীমাতে ক্যালেন্ডার ইউনিট (years,months,weeks) থাকলে বা ডিএসটি (DST) সীমা অতিক্রম করলে,relativeToহিসেবেPlainDateবাZonedDateTimeপাস করতে হবে।
- মানুষ বনাম মেশিনের জন্য ফর্ম্যাট:
- ব্যবহারকারী নিজে ইন্টার্যাক্ট করতে পারেন এমন স্থানীয়করণ করা টেক্সটের জন্য
duration.toLocaleString(locale, options)(যাIntl.DurationFormat-এ ডেলিগেট করে) ব্যবহার করুন। - শুধুমাত্র মেশিনের ক্ষেত্রে গ্রহণযোগ্য ISO 8601 সময়সীমা স্ট্রিংয়ের (যেমন
P1M2DT4H) জন্যduration.toString()ব্যবহার করুন।
- ব্যবহারকারী নিজে ইন্টার্যাক্ট করতে পারেন এমন স্থানীয়করণ করা টেক্সটের জন্য
উদাহরণ: ট্রায়ালের মেয়াদ শেষ হওয়ার ডিফারেনশিয়াল ও স্থানীয় ফর্ম্যাটিং
// 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পাস করুন। `${dateStr}T${timeStr}`-এর মতো ISO স্ট্রিং ইন্টারপোলেট করার পরিবর্তে, টেম্পোরাল মেথড, যেমনTemporal.PlainDate.from(dateStr).toPlainDateTime(timeStr).toZonedDateTime(tz)বাTemporal.PlainDate.from(dateStr).toZonedDateTime({ timeZone: tz, plainTime: timeStr })-এর সাহায্যে আলাদা তারিখ ও সময়ের স্ট্রিং কম্বাইন করুন।- DO
largestUnit(যেমন,'day','month','year').since(),.until()বা.round()-এ পাস করুন যখন আপনি ঘণ্টার বাইরে সময়কাল ব্যালেন্স করতে চান;ZonedDateTimeপার্থক্য পদ্ধতি ডিফল্ট হিসেবে'hour'-এ সেট করা থাকে। - দুটি সময়সীমার তুলনা করার সময়
Temporal.Duration.compare(d1, d2, { relativeTo })ব্যবহার করুন, যেকোনও সময়সীমার সাথে ক্যালেন্ডার ইউনিট (months,years) বা টাইম-জোন-অ্যাওয়ার দিন যুক্ত থাকলেrelativeToঅ্যাঙ্কর প্রদান করুন। - ব্যবহারকারীকে দেখানোর জন্য
${duration.years}y ${duration.months}m...ম্যানুয়ালি ইন্টারপোলেট করার পরিবর্তেduration.toLocaleString()বাnew Intl.DurationFormat(locale, { style })('long','short','narrow'বা'digital') ব্যবহার করে সময়সীমা ফর্ম্যাট করুন। - মেশিনের ক্ষেত্রে গ্রহণযোগ্য ISO 8601 সময়সীমা স্ট্রিংয়ের (যেমন,
PT1H30M) জন্যduration.toString()ব্যবহার করুন, ব্যবহারকারী নিজে ইন্টার্যাক্ট করতে পারেন এমন কপি হিসেবে কখনও নয়। .slice(0, 5)স্ট্রিংয়ের পরিবর্তে.toPlainTime().toString({ smallestUnit: 'minute' })ব্যবহার করেPlainTime-কেHH:MMহিসেবে রেন্ডার করুন (যেমন,<input type="time">-এর জন্য)।- সরাসরি ইনস্ট্যান্স পরিবর্তন করবেন না;
Temporalঅবজেক্ট পরিবর্তন করা যায় না।.add(),.subtract(),.round()বা.with()-এর মতো অপারেশন নতুন ইনস্ট্যান্স রিটার্ন করে। - ডিফারেন্সিয়ালের জন্য
Date/.getTime()অ্যারিথমেটিকে ফিরে যাবেন না;Date-এ টাইম-জোন-অ্যাওয়ার ক্যালেন্ডার ম্যাথ নেই এবং শুধুমাত্র মিলিসেকেন্ড প্রিসিশন আছে। - কোনও সময়সীমা অতীত/মেয়াদ শেষ হয়ে যাওয়া সময় (
sign < 0) নাকি ভবিষ্যতে শুরু হবে এমন সময়কে বোঝাচ্ছে তা চেক করতে, গণনা করাTemporal.Duration(বাTemporal.ZonedDateTime.compare())-এর নেটিভ.signপ্রপার্টি ব্যবহার করুন।
ফলব্যাক স্ট্র্যাটেজি
টেম্পোরালের জন্য ফলব্যাক ও ব্রাউজার সহায়তা
যেসব ব্রাউজার এখনও নেটিভ Temporal API সাপোর্ট করে না, সেগুলির জন্য ফিচার শনাক্তকরণ ব্যবহার করুন এবং ডায়নামিকভাবে temporal-polyfill (~15 KB 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();
})();