Dấu thời gian Unix (Unix timestamp) là số giây đã trôi qua kể từ 00:00:00 UTC ngày 1 tháng 1 năm 1970, gọi là epoch. Nhiều hệ thống lại đếm bằng đơn vị nhỏ hơn, và cách nhanh nhất để phân biệt là đếm số chữ số của một giá trị thời nay: 10 chữ số là giây, 13 là mili giây, 16 là micro giây và 19 là nano giây. Đọc giá trị mili giây như giây, bạn sẽ ra một năm cỡ 55.000; đọc giây như mili giây, bạn ra tháng 1 năm 1970. Bài này giải thích epoch, các đơn vị và quy tắc đếm chữ số cùng giới hạn của nó, cho thấy vì sao dấu thời gian không có múi giờ còn ngày giờ thì có, nói về ISO 8601, và kết thúc bằng lỗi năm 2038.
Epoch là gì
1700000000 là thời điểm 22:13:20 UTC ngày 14 tháng 11 năm 2023. Số không là epoch, 00:00:00 UTC ngày 1 tháng 1 năm 1970, còn số âm là các thời điểm trước đó: -86400 là ngày 31 tháng 12 năm 1969. Dấu thời gian là một con số duy nhất cho một thời điểm duy nhất trên thế giới, giống nhau ở mọi múi giờ, vì thế cơ sở dữ liệu, nhật ký, API và hệ thống tệp đều ưa dùng nó.
Giờ Unix bỏ qua giây nhuận. Nó coi mỗi ngày có đúng 86.400 giây, nên một dấu thời gian ứng với đúng một ngày giờ và ngược lại.
Giây, mili giây, micro giây, nano giây
Cùng một thời điểm được các hệ thống khác nhau ghi ra, lấy ngày 14 tháng 11 năm 2023:
| Đơn vị | Giá trị | Số chữ số | Bạn gặp ở đâu |
|---|---|---|---|
| Giây | 1700000000 | 10 | date +%s của Unix, time() của PHP, claim JWT, nhiều cơ sở dữ liệu |
| Mili giây | 1700000000123 | 13 | Date.now() của JavaScript, System.currentTimeMillis() của Java |
| Micro giây | 1700000000123456 | 16 | Một số cơ sở dữ liệu và hệ thống truy vết |
| Nano giây | 1700000000123456789 | 19 | UnixNano() của Go, time.time_ns() của Python |
Tại thời điểm viết bài, thời gian hiện tại khoảng 1791895973 tính bằng giây và 1791895973607 tính bằng mili giây, nên bạn thực sự sẽ gặp các số 10 và 13 chữ số. time.time() của Python trả về giây kèm phần thập phân, như 1700000000.5.
Quy tắc đếm chữ số, và nơi nó hết đúng
Hãy đếm số chữ số của phần nguyên. Công cụ bên dưới đọc đến 11 chữ số là giây, 12 đến 14 là mili giây, 15 đến 17 là micro giây và từ 18 trở lên là nano giây. Các ngưỡng này được chọn để quy tắc đúng với các ngày từ khoảng năm 1973 đến năm 2286:
- Giây 10 chữ số chạy từ
1000000000(9 tháng 9 năm 2001) đến9999999999(20 tháng 11 năm 2286). Thêm một chữ số nữa thì kéo dài đến năm 5138. - Mili giây 13 chữ số bắt đầu từ
1000000000000(cũng là 9 tháng 9 năm 2001) trở đi. Mili giây 12 chữ số lùi tới100000000000, tức 3 tháng 3 năm 1973.
Quy tắc sai với ngày cũ. Dấu thời gian mili giây của năm 1972 có 11 chữ số, và công cụ chỉ dựa vào số chữ số sẽ đọc nó như giây ở năm 5138. Tương tự, dấu thời gian tính bằng giây trước tháng 9 năm 2001 chỉ có 9 chữ số. Nếu làm việc với dữ liệu lịch sử, hãy tự chọn đơn vị thay vì tin vào tự nhận diện.
Hai lỗi kinh điển đối xứng với nhau:
| Việc bạn đã làm | Kết quả với 1700000000 hoặc 1700000000000 |
|---|---|
| Đọc mili giây như giây | 1700000000000 giây là khoảng năm 55.841 |
| Đọc giây như mili giây | 1700000000 mili giây là 20 tháng 1 năm 1970, 16:13:20 UTC |
Thấy năm 1970 ở chỗ bạn mong một ngày gần đây, hoặc một năm hàng chục nghìn, thì chỉ một bước là nhận ra lỗi này.
Dấu thời gian không có múi giờ, ngày giờ thì có
Cùng 1700000000 hiện ra các giờ đồng hồ khác nhau tùy bạn ở đâu:
| Múi giờ | Chênh lệch | Ngày và giờ |
|---|---|---|
| UTC | +00:00 | 14/11/2023, 22:13:20 |
| TP. Hồ Chí Minh | +07:00 | 15/11/2023, 05:13:20 |
| New York | -05:00 | 14/11/2023, 17:13:20 |
| Tokyo | +09:00 | 15/11/2023, 07:13:20 |
Lưu ý ở TP. Hồ Chí Minh đã sang ngày hôm sau. Lỗi báo "sai ngày" thường là do dấu thời gian được chuyển ở sai múi giờ. Hãy lưu và trao đổi dấu thời gian, hoặc ngày giờ UTC, và chỉ áp múi giờ khi hiển thị.
ISO 8601 trong thực tế
ISO 8601 là định dạng ngày giờ được thiết kế để tránh nhập nhằng: năm trước, rồi tháng, ngày, chữ T, sau đó là giờ và độ lệch múi giờ. Cùng một thời điểm có thể viết theo hai cách:
2023-11-14T22:13:20Z
2023-11-15T05:13:20+07:00Z nghĩa là UTC, còn +07:00 nghĩa là sớm hơn UTC bảy giờ. Cả hai đều đúng bằng 1700000000. Ngày giờ không có Z hay độ lệch thì mơ hồ: nó nêu một số đọc trên đồng hồ chứ không phải một thời điểm. JavaScript còn có một điểm lạ riêng: new Date("2023-11-15") được đọc là nửa đêm UTC, trong khi new Date("2023-11-15T00:00:00") được đọc là nửa đêm theo múi giờ địa phương. Trên máy đặt giờ TP. Hồ Chí Minh, kết quả thứ hai là 17:00 UTC ngày 14. Hãy luôn viết độ lệch khi ngày giờ sẽ được chuyển sang hệ thống khác.
Giờ mùa hè: những giờ không tồn tại
Ở nơi đồng hồ được chỉnh, có những số đọc không bao giờ xuất hiện và có số đọc xuất hiện hai lần. Ở New York ngày 10 tháng 3 năm 2024, đồng hồ nhảy từ 02:00 lên 03:00, nên 2024-03-10 02:30 không hề tồn tại; công cụ dời nó về 03:30 và báo cho bạn biết. Ngày 3 tháng 11 năm 2024 đồng hồ lùi từ 02:00 về 01:00, nên 01:30 xảy ra hai lần, lúc 05:30 UTC và lần nữa lúc 06:30 UTC; công cụ dùng lần sớm hơn và cũng báo như vậy. Bài học cho lịch chạy và nhật ký là giữ dấu thời gian gốc theo UTC. Bảng tra cứu biểu thức cron cho thấy hiệu ứng này tác động lên các tác vụ định kỳ ra sao.
Lỗi năm 2038
Số nguyên có dấu 32 bit chứa được giá trị đến 2.147.483.647. Tính như dấu thời gian theo giây, đó là 2038-01-19 03:14:07 UTC. Một giây sau, bộ đếm quay vòng về -2.147.483.648, tức 20:45:52 UTC ngày 13 tháng 12 năm 1901. Những hệ thống còn giữ giây trong trường 32 bit có dấu, như thiết bị nhúng cũ, một số định dạng tệp và cột cơ sở dữ liệu khai báo kiểu số nguyên 32 bit, khi đó sẽ hiện ngày của năm 1901.
Bộ đếm 32 bit không dấu kéo dài đến 06:28:15 UTC ngày 7 tháng 2 năm 2106. Bộ đếm 64 bit xóa sạch vấn đề này cho mọi mục đích thực tế: nó tràn sau khoảng 292 tỷ năm nữa. Cách sửa là dùng giá trị thời gian 64 bit, và kiểm tra kiểu của mọi cột, mọi trường lưu dấu thời gian. Mili giây trong trường 32 bit tràn sớm hơn nhiều, chưa đến 25 ngày sau epoch.
Chuyển đổi bằng công cụ
- Mở công cụ đổi dấu thời gian. Gõ hoặc dán một giá trị vào ô duy nhất: số được đọc như dấu thời gian, ngày được đọc như ngày. Khi ô trống, công cụ hiện thời gian hiện tại và cập nhật mỗi giây; tắt "Đồng hồ trực tiếp" để dừng lại, hoặc bấm Bây giờ.
- Xem ghi chú dưới ô, ví dụ "Đã đọc là Mili giây (13 chữ số)". Nếu đoán sai đơn vị, hãy chọn Giây, Mili giây, Micro giây hoặc Nano giây ở "Đơn vị dấu thời gian".
- Chọn Múi giờ. Mặc định là múi giờ thiết bị của bạn. Ngày gõ không kèm độ lệch được đọc theo múi giờ đã chọn; ngày có
Zhoặc độ lệch như+07:00thì mang theo múi giờ riêng. - Sao chép bất kỳ dòng nào: giây Unix, mili giây, micro giây, nano giây, ISO 8601 theo UTC và theo múi giờ, RFC 2822, dạng dễ đọc, và dạng tương đối như "3 ngày trước".
Công cụ nhận các năm từ 1 đến 9999 và tính toán hoàn toàn trong trình duyệt, bằng dữ liệu múi giờ mà trình duyệt đã có sẵn. Trường exp của JWT là một giá trị giây như vậy; cách đọc một JWT áp dụng điều đó. Các mã định danh sắp theo thời gian cũng mang dấu thời gian mili giây, như bài so sánh UUID v4, v7 và ULID cho thấy.
Công thức dòng lệnh và mã
date +%s # bây giờ, tính bằng giây
date -u -r 1700000000 # macOS: giây sang ngày giờ UTC
date -u -d @1700000000 # GNU/Linux: tương tựDate.now(); // mili giây
new Date(1700000000 * 1000).toISOString(); // "2023-11-14T22:13:20.000Z"
Math.floor(Date.now() / 1000); // giâyTrong bảng tính, =A2/86400+25569 biến dấu thời gian tính bằng giây thành ngày giờ khi ô được định dạng là ngày, vì 25569 là số ngày giữa ngày số không của Excel và năm 1970.
Danh sách kiểm tra ngắn
Đếm số chữ số trước khi chuyển đổi, và tự chọn đơn vị cho ngày trước năm 1973. Lưu thời gian dưới dạng dấu thời gian UTC và chỉ áp múi giờ khi hiển thị. Viết ISO 8601 kèm độ lệch khi trao đổi ngày giờ. Cẩn thận với các số đọc đồng hồ quanh lúc đổi giờ mùa hè, và dùng trường 64 bit cho mọi thứ phải còn chạy sau tháng 1 năm 2038.