I visualizzatori log, le cronologie di controllo e le UI di telemetria spesso importano eventi i cui timestamp ISO 8601 sono stati registrati con precisione in microsecondi o nanosecondi da un server, un database o un orologio nativo (ad esempio, 2026-04-01T12:00:00.000123456Z). Poiché l'oggetto Date legacy memorizza solo i millisecondi, l'analisi di queste stringhe con new Date() o Date.parse() tronca silenziosamente le cifre inferiori al millisecondo, causando la collisione e l'ordinamento instabile di eventi distinti nello stesso millisecondo.
Temporal.Instant rappresenta un punto esatto nella cronologia UTC con precisione al nanosecondo e senza fuso orario associato. Quando analizza i timestamp ad alta precisione preregistrati con Temporal.Instant.from(), conserva il valore completo dei nanosecondi, ordina in modo deterministico con Temporal.Instant.compare() e calcola gli intervalli Temporal.Duration esatti tra gli eventi. Tieni presente che nei browser Temporal.Now.instant() è deliberatamente limitato alla risoluzione in millisecondi o microsecondi per la mitigazione degli attacchi di temporizzazione Spectre. Utilizza Temporal.Instant.from() per conservare i timestamp in nanosecondi prodotti da orologi esterni e utilizza performance.now() quando misuri intervalli inferiori al millisecondo localmente nel client.
Modalità di implementazione
Per analizzare, ordinare e misurare gli intervalli tra timestamp ad alta precisione:
- Analizza i timestamp registrati come
Temporal.Instant: utilizzaTemporal.Instant.from(isoString)sulla stringa del timestamp fornita dal server, dal database o dalla riga di log. Mantieni il timestamp registrato dall'origine; non sostituirlo conTemporal.Now.instant()nel browser. - Ordina gli eventi in ordine cronologico: utilizza
Temporal.Instant.compare(a, b)come comparatore passato aArray.prototype.sort()oArray.prototype.toSorted(). Confronta il valore completo dei nanosecondi in modo da preservare l'ordine dei sottomillisecondi. - Calcola gli intervalli: utilizza
instant.since(previousInstant)per ottenere unTemporal.Durationtra eventi consecutivi. Utilizzaa.equals(b)per rilevare gli eventi con timestamp identici. - Visualizza gli intervalli con
toLocaleString(): formattaTemporal.Durationper gli utenti conduration.toLocaleString(), che delega aIntl.DurationFormat. Non convertire in un singoloNumberdi nanosecondi per la visualizzazione. - Serializza per la trasmissione: utilizza
Temporal.Instant.prototype.toString()per generare una stringa ISO 8601 standard (sempre in UTC con un suffissoZ).
Esempio di codice: ordinamento dei timestamp ad alta precisione
// 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));
Implementazione strategica e best practice
- SÌ: utilizza
Temporal.Instant.from()per analizzare i timestamp ad alta precisione registrati su un singolo orologio (ad esempio un server, un database o una pipeline di log) che devono essere ordinati o differenziati. A differenza diTemporal.PlainDateTime,Temporal.Instantrappresenta un punto univoco nella cronologia universale. - SÌ: mantieni il timestamp registrato dall'origine. Nei browser,
Temporal.Now.instant()è limitato alla precisione in millisecondi/microsecondi per la mitigazione degli attacchi di temporizzazione Spectre e del fingerprinting; utilizzaperformance.now()/performance.mark()per gli intervalli client locali inferiori al millisecondo eTemporal.Instant.from()per l'analisi dei timestamp in nanosecondi dai clock del server o nativi. - USA
Temporal.Instant.compare()per l'ordinamento ea.equals(b)per i controlli di uguaglianza; non controllareTemporal.Instant.compare(a, b) === 0o confrontare l'output di.toString(). - NON analizzare stringhe di timestamp ad alta precisione con
new Date()oDate.parse()per l'ordinamento, perché vengono troncate in millisecondi e generano collisioni. - NON comprimere un intervallo in un singolo numero per la visualizzazione.
duration.total('nanoseconds')restituisce unNumber, che superaNumber.MAX_SAFE_INTEGERper intervalli superiori a circa 104 giorni e perde silenziosamente precisione. La sottrazione diepochNanoseconds(unBigInt) è esatta, ma ignora la struttura dell'unità; mantieni gli intervalli comeTemporal.Duratione formattali con.toLocaleString(). - SÌ: converti un
InstantinTemporal.ZonedDateTimeconinstant.toZonedDateTimeISO(timeZone)quando devi mostrare a un utente l'ora locale di un evento.
Strategia di riserva
Fallback e supporto del browser per Temporal
Per i browser che non supportano ancora l'API Temporal nativa, utilizza il rilevamento delle funzionalità e carica dinamicamente temporal-polyfill (~15 kB min+gz).
Tieni presente che l'importazione di temporal-polyfill non assegna automaticamente l'oggetto Temporal all'ambito globale. Assegnalo esplicitamente se il tuo codice si basa su 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();
})();