Temporal.Instant-এর সাহায্যে হাই-প্রিসিশন টাইমস্ট্যাম্প সাজানো

ওয়েব ফিচার: Temporal

লগ ভিউয়ার, অডিট টাইমলাইন এবং টেলিমেট্রি UI প্রায়ই এমন ইভেন্ট ইনজেস্ট করে যার ISO 8601 টাইমস্ট্যাম্প কোনও সার্ভার, ডেটাবেস বা নেটিভ ক্লক (যেমন, 2026-04-01T12:00:00.000123456Z) দ্বারা মাইক্রোসেকেন্ড বা ন্যানোসেকেন্ডের নির্ভুলতার সাথে রেকর্ড করা হয়েছে। যেহেতু লিগ্যাসি Date অবজেক্ট শুধুমাত্র মিলিসেকেন্ড স্টোর করে, তাই new Date() বা Date.parse()-এর মাধ্যমে সেইসব স্ট্রিং পার্স করলে সাব-মিলিসেকেন্ড ডিজিট সাইলেন্টলি ট্রাঙ্কেট হয়ে যায়, যার ফলে একই মিলিসেকেন্ডের মধ্যে স্বতন্ত্র ইভেন্টগুলি একে অপরের সাথে ওভারল্যাপ করে এবং একটি অস্থির ক্রমে সাজানো হয়।

Temporal.Instant ন্যানোসেকেন্ড নির্ভুলতা সহ UTC টাইমলাইনে একটি সঠিক পয়েন্ট উপস্থাপন করে এবং কোনও টাইম জোন অ্যাটাচ করা নেই। Temporal.Instant.from()-এর মাধ্যমে আগে থেকে রেকর্ড করা হাই-প্রিসিশন টাইমস্ট্যাম্প পার্স করার সময়, এটি সম্পূর্ণ ন্যানোসেকেন্ড ভ্যালু সংরক্ষণ করে, Temporal.Instant.compare()-এর মাধ্যমে নির্ধারকভাবে সাজায় এবং ইভেন্টের মধ্যে সঠিক Temporal.Duration ইন্টারভ্যাল গণনা করে। মনে রাখবেন যে ব্রাউজারে, স্পেক্টার টাইমিং-অ্যাটাক প্রশমনের জন্য Temporal.Now.instant() ইচ্ছাকৃতভাবে মিলি-সেকেন্ড বা মাইক্রো-সেকেন্ড রেজোলিউশনে ক্ল্যাম্প করা হয়—এক্সটার্নাল ক্লক দ্বারা তৈরি ন্যানো-সেকেন্ড টাইমস্ট্যাম্প সংরক্ষণ করতে Temporal.Instant.from() ব্যবহার করুন এবং ক্লায়েন্টে স্থানীয়ভাবে সাব-মিলি-সেকেন্ড ইন্টারভাল পরিমাপ করার সময় performance.now() ব্যবহার করুন।

কীভাবে প্রয়োগ করতে হয়

হাই-প্রিসিশন টাইমস্ট্যাম্পের মধ্যে ব্যবধান পার্স, সাজানো এবং পরিমাপ করতে:

  1. রেকর্ড করা টাইমস্ট্যাম্প Temporal.Instant হিসেবে পার্স করুন: সার্ভার, ডেটাবেস বা লগ লাইনের মাধ্যমে প্রদান করা টাইমস্ট্যাম্প স্ট্রিংয়ে Temporal.Instant.from(isoString) ব্যবহার করুন। সোর্স যে টাইমস্ট্যাম্প রেকর্ড করেছে সেটিই রাখুন; ব্রাউজারে এটি Temporal.Now.instant() দিয়ে পরিবর্তন করবেন না।
  2. ইভেন্টগুলি কালানুক্রমিকভাবে সাজান: Array.prototype.sort() বা Array.prototype.toSorted()-এ পাস করা তুলনাকারী হিসেবে Temporal.Instant.compare(a, b) ব্যবহার করুন। এটি সম্পূর্ণ ন্যানোসেকেন্ড ভ্যালু তুলনা করে যাতে সাব-মিলিসেকেন্ড অর্ডার সংরক্ষিত থাকে।
  3. ইন্টারভ্যাল গণনা করা: পরপর ইভেন্টের মধ্যে Temporal.Duration পেতে instant.since(previousInstant) ব্যবহার করুন। একই টাইমস্ট্যাম্প সহ ইভেন্ট শনাক্ত করতে a.equals(b) ব্যবহার করুন।
  4. toLocaleString()-এর সাথে ইন্টারভাল দেখান: duration.toLocaleString()-এর সাথে ব্যবহারকারীদের জন্য Temporal.Duration ফর্ম্যাট করুন, যা Intl.DurationFormat-এ ডেলিগেট করে। দেখানোর জন্য ন্যানোসেকেন্ডের একটি Number-এ কনভার্ট করবেন না।
  5. ট্রান্সমিশনের জন্য সিরিয়ালাইজ করা: স্ট্যান্ডার্ড ISO 8601 স্ট্রিং (সবসময় UTC-তে Z সাফিক্স সহ) এমিট করতে Temporal.Instant.prototype.toString() ব্যবহার করুন।

উদাহরণ কোড: হাই-প্রিসিশন টাইমস্ট্যাম্প সাজানো

// Events received with nanosecond-precision ISO 8601 timestamps.
const rawEvents = [
  { nodeId: 'api-2', eventType: 'db.query', ts: '2026-04-01T12:00:00.000123456Z' },
  { nodeId: 'api-1', eventType: 'request.start', ts: '2026-04-01T12:00:00.000120000Z' },
  { nodeId: 'api-2', eventType: 'request.end', ts: '2026-04-01T12:00:00.000987654Z' },
];

// 1. Parse recorded timestamps as Temporal.Instant (never `new Date(ts)`,
// which drops everything below the millisecond).
const events = rawEvents.map(evt => ({
  ...evt,
  timestamp: Temporal.Instant.from(evt.ts),
}));

// 2. Sort chronologically with the static compare() method
function sequenceEvents(items) {
  // Instant.compare returns -1, 0, or 1, which is what sort() expects.
  return [...items].sort((a, b) => Temporal.Instant.compare(a.timestamp, b.timestamp));
}

// 3. Calculate and display the interval between consecutive events
function analyzeTrace(sortedEvents) {
  for (let i = 1; i < sortedEvents.length; i++) {
    const prev = sortedEvents[i - 1];
    const curr = sortedEvents[i];

    // since() returns a Temporal.Duration that retains nanosecond precision.
    const gap = curr.timestamp.since(prev.timestamp);

    // 4. toLocaleString() formats the duration for people (e.g., "3μs 456ns").
    // Avoid gap.total('nanoseconds'): spans over ~104 days exceed Number.MAX_SAFE_INTEGER.
    // 'en-US' is used here for deterministic output; pass undefined to use the user's locale.
    console.log(`${prev.eventType} → ${curr.eventType}: ${gap.toLocaleString('en-US', { style: 'narrow' })}`);
  }
}

analyzeTrace(sequenceEvents(events));

স্ট্র্যাটেজিক প্রয়োগ ও পেশাদার পদ্ধতি

  • একটি ঘড়ির (যেমন, সার্ভার, ডেটাবেস বা লগ পাইপলাইন) বিপরীতে রেকর্ড করা হাই-প্রিসিশন টাইমস্ট্যাম্প পার্স করার জন্য Temporal.Instant.from() ব্যবহার করুন, যেগুলি অর্ডার বা পার্থক্য করতে হবে। Temporal.PlainDateTime-এর মতো নয়, Temporal.Instant ইউনিভার্সাল টাইমলাইনে একটি দ্ব্যর্থহীন পয়েন্টকে দেখায়।
  • সোর্স দ্বারা রেকর্ড করা টাইমস্ট্যাম্প রাখুন। ব্রাউজারে, স্পেক্টার টাইমিং-অ্যাটাক এবং ফিঙ্গারপ্রিন্টিং প্রশমনের জন্য Temporal.Now.instant() মিলিসেকেন্ড/মাইক্রোসেকেন্ড নির্ভুলতায় ক্ল্যাম্প করা হয়; স্থানীয় সাব-মিলিসেকেন্ড ক্লায়েন্ট ইন্টারভ্যালের জন্য performance.now() / performance.mark() ব্যবহার করুন এবং সার্ভার বা নেটিভ ঘড়ি থেকে ন্যানোসেকেন্ড টাইমস্ট্যাম্প পার্স করার জন্য Temporal.Instant.from() ব্যবহার করুন।
  • সর্ট করার জন্য Temporal.Instant.compare() এবং সমতা চেক করার জন্য a.equals(b) ব্যবহার করুন; Temporal.Instant.compare(a, b) === 0 চেক করবেন না বা .toString() আউটপুট তুলনা করবেন না।
  • অর্ডার করার জন্য new Date() বা Date.parse()-এর সাথে হাই-প্রিসিশন টাইমস্ট্যাম্প স্ট্রিং পার্স করবেন না, কারণ সেগুলি মিলিসেকেন্ডে ট্রাঙ্কেট করে এবং সংঘর্ষ তৈরি করে।
  • দেখানোর জন্য কোনও ইন্টারভ্যালকে একটি নম্বরে সংক্ষিপ্ত করবেন না। duration.total('nanoseconds') একটি Number রিটার্ন করে, যা ~১০৪ দিনের বেশি স্প্যানের জন্য Number.MAX_SAFE_INTEGER-এর বেশি এবং নিঃশব্দে নির্ভুলতা হারায়। epochNanoseconds (একটি BigInt) বিয়োগ করলে সঠিক ফলাফল পাওয়া যায় কিন্তু ইউনিট স্ট্রাকচার বাদ যায়; ব্যবধান Temporal.Duration হিসেবে রাখুন এবং .toLocaleString() দিয়ে ফর্ম্যাট করুন।
  • ব্যবহারকারীকে কোনও ইভেন্টের স্থানীয় সময় দেখানোর প্রয়োজন হলে, instant.toZonedDateTimeISO(timeZone)-এর সাথে Instant-কে Temporal.ZonedDateTime-এ পরিবর্তন করুন।

ফলব্যাক স্ট্র্যাটেজি

টেম্পোরালের জন্য ফলব্যাক ও ব্রাউজার সহায়তা

যেসব ব্রাউজার এখনও নেটিভ 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();
})();