מציגי יומנים, צירי זמן של ביקורת וממשקי משתמש של טלמטריה מקבלים לעיתים קרובות אירועים שחותמות הזמן שלהם בפורמט 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() מוגבל בכוונה לרזולוציה של אלפיות השנייה או מיליוניות השנייה כדי לצמצם את הסיכון למתקפת תזמון מסוג 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לפרקי זמן ארוכים יותר מ-104 ימים בערך, ומאבד את הדיוק בלי להציג הודעה. החיסור שלepochNanoseconds(BigInt) הוא מדויק אבל מתעלם ממבנה היחידה. צריך להשאיר את המרווחים בתורTemporal.Durationולעצב אותם באמצעות.toLocaleString(). - מומלץ להמיר
Instantל-Temporal.ZonedDateTimeבאמצעותinstant.toZonedDateTimeISO(timeZone)כשצריך להציג למשתמש את השעה המקומית של אירוע.
אסטרטגיית גיבוי
תמיכה ב-Temporal בדפדפנים ופתרונות חלופיים
בדפדפנים שעדיין לא תומכים ב-API המקורי של Temporal, צריך להשתמש בזיהוי תכונות ולטעון באופן דינמי את 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();
})();