Trình xem nhật ký, dòng thời gian kiểm tra và giao diện người dùng đo từ xa thường nhập các sự kiện có dấu thời gian ISO 8601 được máy chủ, cơ sở dữ liệu hoặc đồng hồ gốc ghi lại với độ chính xác đến micrô giây hoặc nano giây (ví dụ: 2026-04-01T12:00:00.000123456Z). Vì đối tượng Date cũ chỉ lưu trữ mili giây, nên việc phân tích cú pháp các chuỗi đó bằng new Date() hoặc Date.parse() sẽ tự động cắt bớt các chữ số dưới mili giây, khiến các sự kiện riêng biệt trong cùng một mili giây xung đột và sắp xếp theo thứ tự không ổn định.
Temporal.Instant biểu thị một điểm chính xác trên dòng thời gian UTC với độ chính xác đến nano giây và không có múi giờ đi kèm. Khi phân tích cú pháp dấu thời gian có độ chính xác cao được ghi trước bằng Temporal.Instant.from(), dấu thời gian này sẽ giữ nguyên giá trị nano giây đầy đủ, sắp xếp một cách tất định bằng Temporal.Instant.compare() và tính toán khoảng thời gian Temporal.Duration chính xác giữa các sự kiện. Xin lưu ý rằng trong các trình duyệt, Temporal.Now.instant() được cố ý giới hạn giá trị ở độ phân giải mili giây hoặc micrô giây để giảm nhẹ cuộc tấn công định thời Spectre – hãy sử dụng Temporal.Instant.from() để giữ lại dấu thời gian nano giây do đồng hồ bên ngoài tạo ra và sử dụng performance.now() khi đo lường khoảng thời gian dưới mili giây cục bộ trong ứng dụng.
Cách triển khai
Để phân tích cú pháp, sắp xếp và đo lường khoảng thời gian giữa các dấu thời gian có độ chính xác cao:
- Phân tích cú pháp dấu thời gian đã ghi lại dưới dạng
Temporal.Instant: Sử dụngTemporal.Instant.from(isoString)trên chuỗi dấu thời gian do máy chủ, cơ sở dữ liệu hoặc dòng nhật ký cung cấp. Giữ dấu thời gian mà nguồn đã ghi lại; không thay thế bằngTemporal.Now.instant()trong trình duyệt. - Sắp xếp sự kiện theo trình tự thời gian: Sử dụng
Temporal.Instant.compare(a, b)làm trình so sánh được truyền đếnArray.prototype.sort()hoặcArray.prototype.toSorted(). Hàm này so sánh toàn bộ giá trị nano giây để giữ nguyên thứ tự dưới mili giây. - Tính khoảng thời gian: Sử dụng
instant.since(previousInstant)để nhậnTemporal.Durationgiữa các sự kiện liên tiếp. Hãy sử dụnga.equals(b)để phát hiện các sự kiện có dấu thời gian giống hệt nhau. - Hiển thị khoảng thời gian bằng
toLocaleString(): Định dạngTemporal.Durationcho người dùng bằngduration.toLocaleString(), uỷ quyền choIntl.DurationFormat. Đừng chuyển đổi thành mộtNumbernano giây để hiển thị. - Chuyển đổi tuần tự để truyền: Sử dụng
Temporal.Instant.prototype.toString()để phát ra một chuỗi ISO 8601 chuẩn (luôn ở dạng UTC có hậu tốZ).
Mã ví dụ: Sắp xếp dấu thời gian có độ chính xác cao
// 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));
Triển khai chiến lược và các phương pháp hay nhất
- NÊN sử dụng
Temporal.Instant.from()để phân tích cú pháp dấu thời gian có độ chính xác cao được ghi lại theo một đồng hồ duy nhất (chẳng hạn như máy chủ, cơ sở dữ liệu hoặc quy trình ghi nhật ký) cần được sắp xếp hoặc phân biệt. Không giống nhưTemporal.PlainDateTime,Temporal.Instantbiểu thị một điểm rõ ràng trên dòng thời gian chung. - NÊN giữ dấu thời gian do nguồn ghi lại. Trong trình duyệt,
Temporal.Now.instant()được giới hạn giá trị ở độ chính xác mili giây/micro giây để giảm nhẹ tấn công thời gian Spectre và tạo vân tay số; sử dụngperformance.now()/performance.mark()cho Khoảng thời gian cục bộ của ứng dụng dưới mili giây vàTemporal.Instant.from()để phân tích cú pháp dấu thời gian nano giây từ máy chủ hoặc đồng hồ gốc. - NÊN sử dụng
Temporal.Instant.compare()để sắp xếp vàa.equals(b)để kiểm tra tính bằng nhau; không kiểm tra kết quả đầu raTemporal.Instant.compare(a, b) === 0hoặc so sánh kết quả đầu ra.toString(). - KHÔNG phân tích cú pháp chuỗi dấu thời gian có độ chính xác cao bằng
new Date()hoặcDate.parse()để sắp xếp, vì các chuỗi này sẽ cắt bớt thành mili giây và gây ra xung đột. - KHÔNG thu gọn khoảng thời gian thành một số duy nhất để hiển thị.
duration.total('nanoseconds')trả về mộtNumber, vượt quáNumber.MAX_SAFE_INTEGERcho các khoảng thời gian dài hơn ~104 ngày và mất độ chính xác một cách thầm lặng. Phép trừepochNanoseconds(BigInt) là chính xác nhưng loại bỏ cấu trúc đơn vị; giữ khoảng thời gian làTemporal.Durationvà định dạng chúng bằng.toLocaleString(). - NÊN chuyển đổi
InstantthànhTemporal.ZonedDateTimebằnginstant.toZonedDateTimeISO(timeZone)khi bạn cần hiển thị giờ đồng hồ được bản địa hoá của một sự kiện cho người dùng.
Chiến lược dự phòng
Phương án dự phòng và hỗ trợ trình duyệt cho Temporal
Đối với các trình duyệt chưa hỗ trợ API Temporal gốc, hãy sử dụng tính năng phát hiện tính năng và tải động temporal-polyfill (~15 KB min+gz).
Xin lưu ý rằng việc nhập temporal-polyfill không tự động chỉ định đối tượng Temporal cho phạm vi toàn cục. Hãy chỉ định rõ ràng nếu mã của bạn dựa vào 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();
})();