So sánh RFC 3339 và ISO 8601
(ijmacd.github.io)- Khi xử lý cách biểu diễn ngày giờ, RFC 3339 gần với một tập con hẹp, dễ dùng trên web/Internet, còn ISO 8601-1:2019 bao gồm một tập định dạng rộng hơn nhiều
- Phạm vi so sánh chỉ giới hạn ở ISO 8601-1:2019; các biểu diễn bổ sung trong ISO 8601-2:2019 như mùa, tập hợp, định tính độ bất định, phép toán ngày tháng hiện chưa được phản ánh trong bảng
- Hai tiêu chuẩn cùng bao quát các định dạng ngày giờ cơ bản được dùng rộng rãi như
2026-06-26,14:08:00Z,2026-06-26T14:08:00Z, offset+00:00 - ISO 8601 bao quát cả thế kỷ, thập niên, ngày thứ tự trong năm, ngày theo tuần, thời gian rút gọn, dấu phẩy làm phần thập phân, khoảng thời gian (
P1Y) và phạm vi (2026-06-26/P1Y), nhưng phần lớn các mục này bị loại khỏi RFC 3339 trong bảng - Trong biểu diễn Date-Time, các khác biệt như dấu phân tách
T, chữ hoa/chữ thường và offset-00:00trở thành điểm quyết định khả năng tương thích thực tế giữa các parser
Phạm vi và tiền đề so sánh
- Bảng định dạng không phải là danh sách đầy đủ
- Tiêu chuẩn được xét là ISO 8601-1:2019
- Có những khác biệt quan trọng so với các phiên bản trước và bản nháp
- ISO 8601-2:2019 bao gồm các biểu diễn bổ sung nhưng trang này hiện chưa phản ánh
- Nhóm dưới cấp năm, ví dụ như mùa
- Đơn vị gom nhóm
- Tập hợp
- Định tính độ bất định
- Phép toán ngày tháng
- RFC 3339 đề xuất rằng các tiêu chuẩn con có thể thay
Tbằng ký tự khác, nhưng ví dụ chỉ đưa ra ký tự khoảng trắng - Mỗi tiêu chuẩn định nghĩa các định dạng theo mục đích sử dụng; các định dạng khác không được khuyến nghị
ISO 8601 rộng hơn trong biểu diễn ngày tháng
- Cả RFC 3339 và ISO 8601 đều hỗ trợ ngày theo năm-tháng-ngày như
2026-06-26 - ISO 8601 xử lý nhiều cách biểu diễn ngày tháng đa dạng hơn RFC 3339
- Thế kỷ:
20 - Thập niên:
202 - Năm:
2026 - Năm-tháng:
2026-06 - Ngày thứ tự trong năm:
2026-177 - Ngày theo tuần:
2026-W26,2026-W26-5 - Dạng cơ bản:
20260626,2026177,2026W26,2026W265
- Thế kỷ:
- Trong bảng, RFC 3339 không cho phép các định dạng ngày tháng riêng của ISO ở trên
Khác biệt trong biểu diễn thời gian
- Hai tiêu chuẩn cùng cho phép thời gian đến đơn vị giây và offset múi giờ như
14:08:00Z,14:08:00+00:00,14:08:00.372+00:00 - RFC 3339 không phân biệt chữ hoa/chữ thường, nên có thể viết
TvàZlần lượt làt,z- Các phiên bản ISO 8601 trước đây cũng không phân biệt chữ hoa/chữ thường
- ISO 8601 cho phép thêm phần thập phân vào giá trị thời gian nhỏ nhất
- Bảng chủ yếu có ví dụ một chữ số thập phân, nhưng tiêu chuẩn cho phép độ chính xác tùy ý
- Cho phép cả dấu phẩy và dấu chấm làm dấu phân cách thập phân, và chúng có thể thay thế cho nhau trong mọi định dạng
- ISO 8601-1:2019 cho phép bỏ
Ttrong biểu diễn chỉ có thời gian khi không gây mơ hồ - ISO 8601 hỗ trợ các biểu diễn thời gian rút gọn, dạng cơ bản và dùng dấu phẩy thập phân như
14,14:08,14:08:00,140800,T14:08:00,14:08:00,372 - RFC 3339 cho phép offset
-00:00như14:08:00-00:00, nhưng trong bảng ISO 8601 không cho phép điều này
T và dấu phân tách trong Date-Time
- Cả RFC 3339 và ISO 8601 đều cho phép Date-Time như
2026-06-26T14:08:00Zvà2026-06-26T14:08:00+00:00 - Trong biểu diễn Date-Time của ISO 8601,
Tluôn bắt buộc- Các phiên bản trước từng cho phép bỏ
Ttrong Date-Time - Ngay cả ở các phiên bản trước, việc chèn ký tự thay thế như khoảng trắng hoặc dấu gạch dưới cũng không được cho phép
- Các phiên bản trước từng cho phép bỏ
- Trong bảng, RFC 3339 cho phép các biến thể Date-Time sau
tvàzviết thường:2026-06-26t14:08:00z- Dấu phân tách khoảng trắng:
2026-06-26 14:08:00Z - Dấu phân tách gạch dưới:
2026-06-26_14:08:00Z - Offset
-00:00:2026-06-26T14:08:00-00:00
- ISO 8601 xử lý Date-Time rút gọn như
2026-06-26T14,2026-06-26T14:08,2026-06-26T14:08:00,2026-177T14:08,2026-W26-5T14:08, cũng như Date-Time dựa trên ngày thứ tự trong năm và ngày theo tuần
Khoảng thời gian và phạm vi xoay quanh ISO 8601
- Trong bảng, các định dạng khoảng thời gian (Periods) chỉ được đánh dấu cho ISO 8601
- Ví dụ:
P1Y,P1M,P1W,P1D - Ví dụ có thời gian:
PT1H,PT1M,PT1S - Ví dụ kết hợp:
P1Y1M1DT1H1M1S - Ví dụ thập phân:
P1.5Y,P1,5W,PT1.5S
- Ví dụ:
- Các định dạng phạm vi (Ranges) cũng chỉ được đánh dấu cho ISO 8601
- Ngày và khoảng thời gian:
2026-06-26/P1Y - Ngày và ngày:
2026-06-26/2026-06-26 - Khoảng thời gian và ngày:
P1Y/2026-06-26 - Date-Time và khoảng thời gian:
2026-06-26T14:08/P1DT1H - Phạm vi lặp lại:
R/2026-06-26/P1Y,R10/2026-06-26/P1Y
- Ngày và khoảng thời gian:
Khóa định dạng và công cụ kiểm thử
- Bảng định dạng sử dụng các khóa định dạng như
%Y,%M,%D,%h,%m,%s%Y: Year%M: Month%D: Day%V: Week Year%W: Week%w: Week Day%O: Ordinal Day%h: Hour%m: Minute%s: Second%u: Microsecond%n: Nanosecond%Z: giờ theo múi giờ, bao gồm+hoặc-%z: phút theo múi giờ
- Trình kiểm tra định dạng chỉ xác nhận định dạng đầu vào có thuộc một định dạng trong bảng hay không
- Không kiểm tra mọi định dạng có thể có
- ISO 8601 as a Service là dịch vụ dành cho thử nghiệm beta
- Hiện chỉ hỗ trợ Date, Time, DateTime
- Không hỗ trợ Period và Range
- Mã nguồn được công khai trên GitHub
1 bình luận
Ý kiến trên Hacker News
Thật lạ là không có cách nào để chỉ định ngày/giờ trong tương lai theo một múi giờ cụ thể. Ví dụ, có thể bạn muốn lên lịch một cuộc họp vào 6 giờ chiều giờ địa phương London ngày 1 tháng 7 năm 2030, và dù quy tắc múi giờ của Anh thay đổi thế nào trong khoảng thời gian đó, nó vẫn phải là “6 giờ chiều ở London”
Hiện tại Anh dùng khoảng Z+00:00 từ tháng 11 đến tháng 3, và giờ mùa hè Z+01:00 từ tháng 4 đến tháng 10[0], nhưng trước năm 2030 họ cũng có thể áp dụng Giờ Trung Âu[1], thử lại British Double Summer Time[2], hoặc bãi bỏ giờ mùa hè. Vì vậy cùng một “6 giờ chiều” có thể khác đi rất nhiều nếu xét theo một epoch cụ thể
Tôi muốn đưa “6 giờ chiều theo giờ London khi đó” vào một sự kiện lịch, nhưng không có cách tiêu chuẩn và có khả năng tương tác để biểu diễn 2030-07-01 18:00:00 Europe/London
[0] https://en.wikipedia.org/wiki/British_Summer_Time
[1] https://en.wikipedia.org/wiki/Central_European_Time
[2] https://en.wikipedia.org/wiki/British_Summer_Time#Periods_of...
tztrong ngoặc vuông sau chuỗi RFC 3339, và để biểu diễn giờ địa phương thì cũng phải ghi kèm giá trị ước tính của độ lệch UTCVí dụ
2030-07-01 18:00:00 Europe/Londonsẽ trở thành2030-07-01T18:00:00+01:00[Europe/London]. Nếu trước đó quy tắc của Anh thay đổi, timestamp sẽ trở nên “không khớp”, và ứng dụng sẽ quyết định cách xử lý. Tuy nhiên, nếu đặt!trước tên múi giờ trong ngoặc vuông, ứng dụng phải phát hiện vấn đề thay vì mù quáng làm theo độ lệch UTCĐịnh dạng timestamp mở rộng này cũng được dùng trong thư viện Temporal đang được đề xuất của JavaScript[1], và hàm phân tích cú pháp
ZonedDateTime.from()[2] cho phép kiểm soát bằng tùy chọnoffsetxem nên ưu tiên phía nào trong một timestamp không khớp. Việc bỏ qua độ lệch UTC và chỉ ghi múi giờ cũng được hỗ trợ, nhưng có cảnh báo rằng khoảng một giờ bị lặp lại khi chuyển giờ mùa hè là mơ hồ[0] https://www.ietf.org/archive/id/draft-ietf-sedate-datetime-e...
[1] https://tc39.es/proposal-temporal/docs/strings.html#iana-tim...
[2] https://tc39.es/proposal-temporal/docs/ambiguity.html#ambigu...
Nhưng cũng không phải là không thể tưởng tượng việc trong khoảng thời gian đó Scotland tổ chức lại trưng cầu dân ý độc lập rồi gia nhập Giờ Trung Âu, hoặc tạo ra Scottish Standard Time
2023-11-05 01:30:00 America/New_Yorksẽ là một trong hai thời điểm khác nhauTrong lịch, “cùng thời điểm trên đồng hồ treo tường” thường là ý nghĩa mong muốn nên vẫn hợp lý, nhưng có khó khăn về UI khi xử lý các thời điểm kỳ lạ, và có thể bạn sẽ muốn đưa cách giải mơ hồ vào cú pháp. May là những lần chuyển đổi như vậy thường diễn ra lúc nửa đêm, nhưng tôi từng thấy chuyện này trong công việc thực tế
Nếu mời một người ở múi giờ không có giờ mùa hè, thời gian trong lịch của người đó sẽ dao động, và có lúc các đồng nghiệp quốc tế phải chấp nhận điều này
[0]: https://www.rfc-editor.org/rfc/rfc5545#section-3.3.5
Các định dạng ngày-giờ phổ biến được tạo ra để biểu diễn một thời điểm cụ thể, nhưng trong trường hợp này thì thời điểm cụ thể đó vẫn chưa tồn tại. Việc đặc tả ngày/giờ có cấu trúc không tầm thường là chuyện thường gặp, như cuộc họp vào thứ Sáu cuối cùng hằng tháng, cuộc họp hằng tháng bắt đầu vào ngày 31 tháng 1, hoặc hai ngày trước cuối quý
Nếu muốn tạo một tiêu chuẩn bao quát mọi trường hợp mà mọi người có thể nghĩ tới, có lẽ nó sẽ nhanh chóng trở nên phức tạp. Nếu ngày đơn giản, giờ và khoảnh khắc là chưa đủ, có vẻ chỉ còn cách tạo một cấu trúc riêng chứa tất cả các yếu tố cần thiết
Vì đặc tả ISO không được cung cấp miễn phí nên thường tốt hơn là theo RFC, và nhiều triển khai mã nguồn mở cũng dựa trên bản nháp nên khó xem là hoàn toàn thân thiện với mã nguồn mở. Đây cũng là gánh nặng lớn với các nhà phát triển mã nguồn mở.
Nếu bạn tạo thứ gì đó xử lý ngày trong tương lai, gần như lúc nào bạn cũng sẽ muốn lưu thời gian đồng hồ treo tường + vị trí. Đáng tiếc là không có tiêu chuẩn nào cho việc này. Châu Âu và Mỹ có múi giờ khá ổn định nên có thể không cảm nhận rõ, nhưng ở nhiều khu vực, múi giờ thay đổi thường xuyên nên việc lưu offset không ổn định.
13:30 theo đồng hồ treo tường ngày 5 tháng 6 năm 2026, Parislà điều hầu hết mọi người muốn nói, và tùy EU quyết định thế nào về giờ mùa hè, nó có thể là UTC+2 hoặc UTC+1. Nếu là API xử lý thời điểm trong quá khứ thì chỉ cần dùng timestamp POSIX theo đơn vị giây, mili giây, micro giây hoặc nano giây.iCal cũng không tính đến vấn đề một vị trí bị gán lại sang múi giờ khác. Ngoài ra, một tệp iCal đúng chuẩn sẽ chứa toàn bộ dữ liệu múi giờ mà nó tham chiếu, nên khá phiền phức khi chỉ muốn xuất một ngày-giờ đơn lẻ.
[1] https://icalendar.org/iCalendar-RFC-5545/3-3-5-date-time.htm...
2026-06-05T13:30+0200[Europe/Paris]https://www.ietf.org/archive/id/draft-ietf-sedate-datetime-e...
Một phần thường bị các tiêu chuẩn bỏ qua là cách biểu diễn khoảng thời lượng.
Có thể xem mục 5.5.4.2 “Representation of time-interval by duration only”, trang 21 của http://xml.coverpages.org/ISO-FDIS-8601.pdf. Sẽ rất tốt nếu trình phân tích cú pháp JSON của các ngôn ngữ tĩnh có thể định nghĩa trường là khoảng thời lượng và tuần tự hóa nó sang định dạng hợp lệ.
Ví dụ đề xuất của Crystal ở đây: https://github.com/crystal-lang/crystal/issues/11942
Ví dụ, 15 ngày 5 giờ 20 giây là
P15DT5H0M20S, còn 7 tuần làP7W.durationtrong ABNF của Phụ lục A RFC 3339.Ví dụ, nếu viết như
"duration": { "days": 15, "hours": 5, "seconds": 20 }thì trình phân tích cú pháp JSON không cần hiểu ý nghĩa của dữ liệu, việc đó để bộ kiểm tra đầu vào đảm nhiệm là được. Dù JSON biểu diễn dữ liệu này theo cách nào thì cuối cùng vẫn cần một bước chuyển đổi có khả năng thất bại.RFC 3339 và ISO 8601 “buồn cười” ở chỗ chúng chứa nhiều định dạng ngày-giờ trùng lặp về mục đích, nhưng cả hai lại không bao gồm định dạng quá hiển nhiên và được dùng nhiều nhất trên mọi hệ thống là
2023-09-01 15:30:59.Ngoài ra, cả hai tiêu chuẩn đều rất mơ hồ về cách biểu diễn ngày trước Công nguyên và các ngày sau
9999-12-31hoặc trước-9999-01-01, còn các thư viện phổ biến thì thường hoàn toàn không xử lý được. Ngay cả khi có xử lý, hành vi của00-01-01trên thực tế gần như không được định nghĩa.Lịch Gregory kỳ lạ ở chỗ năm sau 1 TCN là 1 CN, và ngoài phần mềm thiên văn chuyên dụng, gần như mọi phần mềm đều không xử lý đúng phạm vi thời gian Unix ngoài tương lai gần. Ngay cả những việc chỉ cần lưu dưới dạng chuỗi như năm sinh và năm mất của Hoàng đế Augustus cũng nên được tiêu chuẩn định nghĩa rõ ràng.
Tbằng dấu cách là đủ. RFC 3339 cũng làm điều tương tự theo cách dài dòng hơn nhiều.Cũng khó chắc rằng
2023-09-01 15:30:59là định dạng ngày-giờ được dùng nhiều nhất. Ngôn ngữ được dùng nhiều nhất là tiếng Trung, và các dấu phân tách riêng như2023年9月1日khá phổ biến.ISO 8601 cho phép các năm trước 1582 hoặc sau 9999 nếu có thỏa thuận chung. Nếu không vừa 4 chữ số thì phải thêm một ký tự dấu ở phía trước. Những ngày như vậy thường không được hỗ trợ vì có ít việc có thể làm một cách có ý nghĩa với chúng, nhưng tôi đã thấy khá nhiều thư viện phân tích cú pháp được triển khai độc lập với C có xử lý chúng.
00-01-01được định nghĩa là ngày 1 tháng 1 năm 1 TCN. ISO 8601 nêu rõ số năm tuân theo lịch Gregory mở rộng ngược về trước (proleptic Gregorian calendar), nên được ngoại suy đến âm vô cực.Tôi hiểu vì sao họ cần một ký tự không phải dấu cách, nhưng ít nhất cũng có thể dùng dấu gạch dưới hoặc dấu chấm. Và vì đây là chuỗi, tôi cũng không hiểu vì sao lại giới hạn phần năm ở bốn chữ số, hy sinh tính phổ quát của định dạng.
Năm 6 chữ số có cảm giác như một giải pháp cho một vấn đề thực ra sẽ không xảy ra, chỉ để trông có vẻ hướng tới tương lai. Công nghệ hiện tại hay chuẩn mực xã hội khó có thể tồn tại thêm 8000 năm.
Giải thích rằng ISO 8601 dùng U+2010 HYPHEN và U+2212 MINUS, còn trong các bộ ký tự không có các ký tự đó thì phải dùng U+2D HYPHEN-MINUS là sai
ISO 8601 thực tế nêu rõ rằng nếu bộ ký tự đích dựa trên ISO/IEC 646 thì trong cả hai trường hợp đều phải dùng ký tự hyphen-minus. Unicode chắc chắn được bao gồm ở đây. Tuy có chút mơ hồ, nhưng trong Unicode cách diễn giải là rõ ràng; có vẻ đây là một cách gián tiếp để chỉ định ánh xạ chuẩn của 646 nhằm bảo đảm khả năng tương thích với các bộ ký tự khác dựa trên 646
Nội dung là: “Tất cả các ký tự dùng trong biểu diễn ngày và giờ đều thuộc repertoire ISO/IEC 646, ngoại trừ ‘hyphen’, ‘minus’, ‘plus-minus’. Trong môi trường dùng repertoire ký tự dựa trên ISO/IEC 646, cả ‘hyphen’ và ‘minus’ đều phải được ánh xạ thành ‘hyphen-minus’”
Unicode dựa trên ISO 8859, và ISO 8859 dựa trên ISO 646, nên có vẻ đúng là trong bộ ký tự Unicode, ý định là dùng U+2D hyphen-minus
Trên Windows, dấu hai chấm là ký tự đặc biệt, nên chuyện không có cách nào đúng theo RFC 3339 khi đưa ngày và giờ vào tên tệp thường khá khó chịu
Giá mà có thể tuân thủ ISO 8601 bằng cách dùng dấu gạch nối cho ngày nhưng bỏ dấu hai chấm. Ví dụ
20230831T1510-0500là hợp lệ và có thể dùng trong tên tệp, nhưng2023-08-31T1510-0500và các biến thể tương tự thì không. Nói thêm, hàmGet-Datecủa PowerShell không hiểu timestamp đầu tiên không có dấu gạch nối và dấu hai chấmĐây là một hình dung trực quan rất hay về chủ đề này
Khi tách phần ngày và giờ, tôi thích dùng khoảng trắng hoặc dấu gạch dưới hơn
T, nhưng để tránh vấn đề với những thứ chỉ xử lý ISO 8601 và để nhất quán, nhìn chung tôi vẫn tiếp tục dùngTT. Vì sẽ không có chuyện vô tình tách những chuỗi kiểu này theoTTôi thắc mắc hai điều. Thứ nhất, cơ sở của năm 6 chữ số là gì? Chẳng phải bất kỳ hệ thống nào được nghĩ ra hiện nay cũng không thể còn tồn tại sau 100.000 năm sao
Thứ hai, ISO 8601 thì đã phổ biến, nhưng RFC 3339 có được dùng và chấp nhận nhiều trong các hệ thống thực tế không?
timechính thức của Golang vàChronocủa Rust có công cụ tích hợp để xử lý RFC 3339, nhưng không có cho RFC 8601Theo tôi nhớ thì RFC 8601 có vấn đề mơ hồ mà RFC 3339 không có, và Python cũng từng gặp vấn đề khi chuyển đổi ngày qua lại vì lý do này
Không có định dạng nào trong đó múi giờ được chỉ định bằng bốn chữ số không có dấu hai chấm, nhưng
date +%ztrả về±NNNN%:z. Liên quan đến việc này, cũng có thể dạydatemặc định xuất ra như sau: https://gist.github.com/d081dad407432d53172e30d0d35c39db$ date2023-08-31T11:15:00-07:00±NNNNlà hợp lệ ngay cả khi không có dấu hai chấm, nếu được dùng như một phần của “định dạng cơ bản”. Tức là toàn bộ định dạng không được có dấu gạch nối hay dấu hai chấm ở bất cứ đâuVì vậy hai dòng sau là tương đương và đều hợp lệ:
2023-09-01T09:40:01+08:0020230901T094001+0800