نمایشگرهای گزارش، خطوط زمانی ممیزی، و واسطهای کاربری دورسنجی اغلب رویدادهایی را دریافت میکنند که مُهرهای زمان ISO 8601 آنها با دقت میکروثانیه یا نانوثانیه توسط سرور، پایگاه داده، یا ساعت بومی (برای مثال، 2026-04-01T12:00:00.000123456Z) ثبت شدهاند. ازآنجاییکه شیء قدیمی Date فقط میلیثانیه را ذخیره میکند، تجزیه آن رشتهها با new Date() یا Date.parse() بهطور پنهانی ارقام زیر میلیثانیه را کوتاه میکند، که باعث میشود رویدادهای متمایز در همان میلیثانیه باهم تداخل پیدا کنند و با ترتیبی ناپایدار مرتب شوند.
Temporal.Instant نشاندهنده نقطهای دقیق در خط زمان «ساعت هماهنگ جهانی» با دقت نانوثانیه و بدون منطقه زمانی پیوستشده است. هنگام تجزیه مُهرهای زمان با دقت بالا که ازقبل ضبط شدهاند با Temporal.Instant.from()، مقدار کامل نانوثانیه را حفظ میکند، بهطور قطعی با Temporal.Instant.compare() مرتب میکند، و فواصل دقیق Temporal.Duration بین رویدادها را محاسبه میکند. توجه داشته باشید که در مرورگرها، Temporal.Now.instant() بهطور عمدی به وضوح میلیثانیه یا میکروثانیه محدود میشود تا حمله زمانبندی Spectre کاهش یابد—از Temporal.Instant.from() برای حفظ مُهرهای زمان نانوثانیه تولیدشده توسط ساعتهای خارجی استفاده کنید، و از performance.now() هنگام اندازهگیری فاصلههای زیر میلیثانیه بهصورت محلی در کلاینت استفاده کنید.
نحوه پیادهسازی
برای تجزیه، مرتبسازی، و اندازهگیری فاصلههای بین مُهرهای زمان با دقت بالا:
- تجزیه مُهرهای زمان ضبطشده بهعنوان
Temporal.Instant: ازTemporal.Instant.from(isoString)در رشته مُهر زمان ارائهشده توسط سرور، پایگاه داده، یا خط گزارش استفاده کنید. مُهر زمان ثبتشده توسط منبع را حفظ کنید؛ آن را باTemporal.Now.instant()در مرورگر جایگزین نکنید. - مرتبسازی رویدادها براساس زمان: از
Temporal.Instant.compare(a, b)بهعنوان مقایسهکننده ارسالشده بهArray.prototype.sort()یاArray.prototype.toSorted()استفاده کنید. این ویژگی مقدار کامل نانوثانیه را مقایسه میکند تا ترتیب زیرمیلیثانیه حفظ شود. - محاسبه فاصلهها: از
instant.since(previousInstant)برای دریافتTemporal.Durationبین رویدادهای متوالی استفاده کنید. ازa.equals(b)برای شناسایی رویدادهایی با مُهر زمان یکسان استفاده کنید. - نمایش فاصلهها با
toLocaleString(): قالببندیTemporal.Durationبرای کاربران باduration.toLocaleString()، که بهIntl.DurationFormatواگذار میشود. برای نمایش، به یکNumberنانوثانیه تبدیل نکنید. - سریالسازی برای انتقال: از
Temporal.Instant.prototype.toString()برای انتشار رشته استاندارد ISO 8601 (همیشه در UTC با پسوندZ) استفاده کنید.
نمونه کد: مرتبسازی مُهرهای زمان با دقت بالا
// 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()برای کاهش اثر انگشت و حمله زمانبندی Spectre به دقت میلیثانیه/میکروثانیه محدود شده است؛ از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را باinstant.toZonedDateTimeISO(timeZone)بهTemporal.ZonedDateTimeتبدیل کنید، وقتی که لازم است زمان محلیشده رویداد را به کاربر نمایش دهید.
راهبرد جایگزین
پشتیبانی مرورگر و بازگشت به حالت قبلی برای Temporal
برای مرورگرهایی که هنوز از Temporal API بومی پشتیبانی نمیکنند، از تشخیص ویژگی استفاده کنید و temporal-polyfill (~۱۵ کیلوبایت 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();
})();