Asia/Saigon là một bí danh chứ không phải một múi giờ, và IANA với CLDR bất đồng về tên chuẩn tắc ở 19 múi giờ. Một định danh múi giờ thực chất là gì, và ai quyết định nó.

Asia/Saigon trông như một cái tên đơn giản và vĩnh viễn cho một địa danh. Nó không phải cả hai. Đó là một khóa tra cứu vào một cơ sở dữ liệu do tình nguyện viên duy trì, sửa đổi không theo lịch cố định nào, và Việt Nam không đơn độc: mười tám múi giờ khác cũng mang đúng kiểu bất đồng ấy giữa các tổ chức đặt tên cho chúng.

Loạt bài này nói về việc đó có nghĩa gì với Odoo, chia làm bốn phần, vì câu trả lời nằm rải trên bốn hệ thống mà mỗi hệ thống lại có quan điểm riêng.

  • Phần 1 (bài này) — một cái tên múi giờ là gì, ai công bố nó, và vì sao Asia/Saigon cùng Asia/Ho_Chi_Minh đều là đáp án đúng cho hai câu hỏi khác nhau.
  • Phần 2 — Python, PostgreSQL, trình duyệt và Odoo mỗi bên biến chuỗi đó thành một độ lệch giờ ra sao, và chúng thôi đồng thuận ở đâu.
  • Phần 3 — Odoo đã đổi những gì về múi giờ từ năm 2020 tới nay, và thay đổi nào đáp xuống nhánh nào.
  • Phần 4 — thứ gì vẫn còn hỏng, nó trông thế nào trong một database production thật, và phải làm gì với nó.

Không có gì bị xóa cả

Điều đầu tiên cần đính chính là cách đặt vấn đề mà ai cũng bắt đầu, kể cả tôi. Không có múi giờ nào bị gỡ bỏ.

Cơ sở dữ liệu múi giờ của IANA, tzdb, có hai loại mục. Một Zone mang dữ liệu thật: độ lệch giờ, các mốc chuyển, ký hiệu viết tắt. Một Link là bí danh trỏ tới một Zone. Việt Nam chỉ có đúng một bộ quy tắc kể từ ngày 13/6/1975, và cơ sở dữ liệu ghi nó đúng một lần:

Link	Asia/Ho_Chi_Minh	Asia/Saigon

Dòng đó nằm trong file backward, ở một mục có tiêu đề “Alternate names for the same location”1. Asia/Saigon và Asia/Ho_Chi_Minh chưa bao giờ là hai thời điểm khác nhau. Cái này là tên gọi của cái kia.

Ngày đó không phải ngẫu nhiên. Chiến tranh kết thúc ngày 30/4/1975, để lại hai miền Bắc và Nam với hai độ lệch giờ khác nhau: miền Nam theo UTC+8 và miền Bắc theo UTC+7. Khoảng sáu tuần sau, các độ lệch giờ được thống nhất. Bản ghi tzdb đặt mốc chuyển vào 16:00 UTC ngày 12/6/1975, khi đồng hồ ở miền Nam lùi từ nửa đêm ngày 13 về 23:00 ngày 12. Việc thống nhất nhà nước chính thức diễn ra vào năm 1976, còn múi giờ thì đã được thống nhất từ trước đó khá lâu.

File backward vốn được thiết kế là tùy chọn. Chính phần đầu của nó ghi rằng tzdb vẫn build tốt với make BACKWARD=, và rằng các bên dùng lại thường vẫn đóng gói kèm nó. Trên một máy có đóng gói kèm, kết quả trên đĩa chẳng có gì đáng chú ý:

/usr/share/zoneinfo/Asia/Saigon -> Ho_Chi_Minh    (symlink 11 byte)
/usr/share/zoneinfo/Asia/Ho_Chi_Minh              (file TZif 351 byte)

Một file bí danh. Thứ biến mất trên Ubuntu 24.04 là cái symlink đó, không phải một múi giờ.

Một vòng rẽ ngắn vào mục Việt Nam

Cái Zone mà các bí danh kia trỏ tới đáng được đọc trực tiếp, vì tzdb là một trong số ít cơ sở dữ liệu ghi lại chính lý lẽ của mình bằng văn xuôi. Phần Việt Nam trong file asia2 trả lời ba câu hỏi mà người ta thường chỉ đoán.

Vì sao là Ho_Chi_Minh chứ không phải Ho_Chi_Minh_City. Chẳng có gì chính trị, chỉ là độ rộng của trường:

Tên tiếng Anh của thành phố đông dân nhất Việt Nam là “Ho Chi Minh City”; dùng Ho_Chi_Minh bên dưới để tránh một cái tên dài quá 14 ký tự.

Dòng chú thích đó là của Arthur David Olson năm 2008. Ngân sách 14 ký tự là một ràng buộc tương thích từ các hệ thống cũ, và đó là lý do một nửa tzdb đọc lên như một cuốn địa danh bị cắt cụt.

Vì sao một múi giờ lại phủ một đất nước từng là hai đất nước. Vì mốc cắt của tzdb là năm 1970 và phạm vi của nó là “những nơi đã đồng thuận kể từ đó”:

Mục Ho Chi Minh là đủ cho hầu hết mục đích vì nó khớp với toàn Việt Nam từ 13/6/1975. […] Với các mốc thời gian ở miền Bắc Việt Nam lùi về tới 1970 (mốc cắt của tzdb), hãy dùng Asia/Bangkok; xem các mục VN trong file zone1970.tab. Với mốc thời gian trước 1970, xem Asia/Hanoi trong file ‘backzone’.

Vậy là Asia/Hanoi có tồn tại, trong backzone, một file mà phần lớn bản phân phối không đóng gói kèm. Nó mang một độ lệch LMT khác (7:03:24 so với 7:06:30 của Ho Chi Minh) và một mốc chuyển năm 1954 mà múi giờ miền Nam không có. Nếu bạn từng thắc mắc vì sao danh sách chọn không có Hà Nội, đó là lý do: với mọi mốc thời gian mà Odoo sẽ lưu, Hà Nội và Thành phố Hồ Chí Minh là cùng một múi giờ.

Dữ liệu đến từ đâu. Danh sách mốc chuyển được dẫn nguồn từ cuốn Lịch Việt Nam: thế kỷ XX-XXI của Trần Tiến Bình, đối chiếu chéo với các văn bản gốc — mục công báo năm 1945 trong đó Bộ trưởng Bộ Nội vụ Võ Nguyên Giáp đưa Việt Nam lùi lại hai giờ, Dụ số 46 năm 1955, Nghị định số 362-TTP năm 1959 — mỗi văn bản kèm một đường dẫn bản chụp ngay trong file. Tám lần đổi độ lệch giờ từ 1906 đến 1975, lần nào cũng có trích dẫn.

Không điều nào trong đó làm đổi độ lệch giờ người dùng của bạn nhìn thấy. Nhưng nó giải thích hình hài của cả vấn đề. Một định danh tzdb là một quyết định biên tập, do một nhóm nhỏ tình nguyện viên đưa ra, bị ràng buộc bởi những thứ như độ rộng trường 14 ký tự và mốc cắt 1970, và được sửa lại bất cứ khi nào có bằng chứng tốt hơn — dữ liệu Việt Nam được chỉnh lần gần nhất năm 2024, từ một cuốn sách ai đó chỉ ra trên mailing list. Không có gì trong chính tài liệu của tzdb quảng cáo các chuỗi này là khóa ổn định.

Nếu nghe như một nền móng kỳ lạ để dựng một cột database lên trên, bài nói “tzdata: Back to the Future!” của John Feminella tại !!Con là mười phút về cách cơ sở dữ liệu này được duy trì và nó thay đổi thường xuyên tới mức nào4. Đó là lời giải thích ngắn gọn rõ nhất cho việc vì sao các định danh múi giờ lại thay đổi, tức chính cái giả định mà hóa ra mọi tầng trong loạt bài này đều đang đặt vào.

Lần đổi tên có mang màu sắc chính trị không

Câu trả lời ngắn nằm trong commit, và nó nhạt hơn câu hỏi nhiều. Asia/Saigon là tên Zone cho tới 6bf3a2a08, ngày 18/3/2008, với toàn bộ thông điệp commit là Saigon -> Ho_Chi_Minh. Phần diff thay dòng này:

-# Saigon's official name is Thanh-Pho Ho Chi Minh, but it's too long.
+# we use Ho_Chi_Minh below to avoid a name of more than 14 characters.

Vậy là file đã ghi nhận việc đổi tên từ nhiều năm trước mà vẫn giữ Saigon, vì cái tên chính thức không vừa. Thứ thay đổi năm 2008 không phải là quan điểm, mà là sự sẵn lòng cắt bớt.

Và đó không phải một quyết định về Việt Nam. Cùng ngày hôm đó Olson commit luôn Calcutta -> Kolkata. Cùng một quy tắc, vài thành phố, một buổi chiều — nguyên tắc của tzdb là “dùng cách viết tiếng Anh phổ thông” của tên hiện tại, và đây là những mục đã tụt lại sau nguyên tắc đó. Asia/Rangoon → Asia/Yangon, America/Godthab → America/Nuuk và Europe/Kiev → Europe/Kyiv theo sau về sau, cũng theo quy tắc ấy.

Ở chỗ tzdb thật sự thiết kế để né chính trị, họ nói rõ, và phạm vi hẹp hơn người ta tưởng7:

Hãy bền vững trước các thay đổi chính trị. Ví dụ, tên thường không gắn với quốc gia, để tránh bất tương thích khi quốc gia đổi tên […] hoặc khi một địa điểm đổi quốc gia.

Định danh né tránh quốc gia, để một lần đổi tên hay đổi chủ quyền không làm hỏng chúng. Thành phố lại là chuyện khác: ở đó tzdb đi theo tên hiện tại. Điều này đáng nhớ suốt phần còn lại của loạt bài, vì chẳng có gì ở đây xóa đi thứ gì cả. Thành phố được đổi tên năm 197610, tzdb bắt kịp năm 2008, và Asia/Saigon tới hôm nay vẫn phân giải được dưới dạng một Link. Thứ rốt cuộc làm hỏng production là một quyết định đóng gói của Debian năm 2023 và một quyết định giữ ổn định khóa của CLDR — cả hai đều thuần kỹ thuật, và cả hai đều cách phần lịch sử kia hàng chục năm.

Vì sao Debian chuyển các bí danh ra ngoài

Bản gốc vẫn đóng gói kèm backward. Vậy ai đã thôi không đóng gói nó?

Debian, một cách có chủ đích, và họ đã báo trước.

Ngòi nổ đến từ chính tzdb. Bản phát hành 2021b mang dòng “Move some backward-compatibility links to ‘backward’"3, một phần của nỗ lực dài hơi nhằm gộp lại các múi giờ vốn đã có mốc thời gian trùng nhau kể từ 1970. Lần sắp xếp lại đó cho các bản phân phối một ranh giới sạch sẽ để đóng gói theo.

Debian nhận lấy nó. Từ tzdata 2023c-8, tháng 8/2023, gói tzdata chính chỉ còn đóng gói các múi giờ theo đúng quy tắc đặt tên hiện hành là vùng địa lý cộng thành phố. Mọi thứ trong backward, mọi bí danh cũ kể cả nguyên họ US/*, chuyển sang một gói mới tên tzdata-legacy5. Debian 12 và Ubuntu 23.10 là nơi phần lớn mọi người lần đầu gặp thay đổi này.

Phần changelog đáng đọc, dù không vì lý do tôi tưởng lúc đầu. Trích NEWS.Debian:

Điều này có thể cần thiết trong trường hợp hệ thống cung cấp dữ liệu có nhận biết múi giờ qua mạng (ví dụ các database SQL).

Dòng đó không xuất hiện cùng lúc với việc tách gói. Việc tách đi kèm 2023c-8 vào tháng 8/2023; mục NEWS xuất hiện ở 2023d-1 vào tháng 1/2024, sau khi người ta đã va phải nó. Báo cáo lỗi đề nghị đưa chuyện này vào release notes nói thẳng: “Người ta đã va phải chuyện này khi đó (#1051973, #1056908), và phản ứng là thêm một mục NEWS.Debian.”

Vậy nên lời cảnh báo kia không phải một dự đoán. Nó là một bản mô tả viết sau khi sự đã rồi, rồi nằm im trong một changelog gần ba năm — đủ lâu để tới lúc nó có thể giúp được bạn thì chẳng còn ai đọc nữa.

Một ghi chú lề, vì nó giải thích một chi tiết gây bối rối. tzdata-legacy còn mang theo cây right/, tức các biến thể có giây nhuận của mọi múi giờ, và đó là lý do phần mô tả gói viết “dữ liệu múi giờ cho TAI trừ mười giây” dù phần lớn mọi người cài nó chỉ vì US/Eastern. Hai thứ chẳng liên quan gì nhau trong một gói, tổng cộng 735 file6.

Tổ chức thứ hai

Nếu câu chuyện dừng ở chuyện đóng gói, đây sẽ là một vấn đề vận hành: database cũ gặp image mới. Nhưng nó không dừng ở đó, vì tzdb không phải tổ chức duy nhất công bố định danh múi giờ.

Unicode CLDR công bố bộ của riêng mình, và các engine trình duyệt không thống nhất về việc có dùng bộ đó hay không: Chrome thì dùng, Firefox đi theo IANA. Phần 2 sẽ đo đạc chuyện đó; điều quan trọng ở đây là có tồn tại một danh sách thứ hai. CLDR giữ chúng trong common/bcp47/timezone.xml9. Mục của Việt Nam:

<type name="vnsgn" description="Ho Chi Minh City, Vietnam"
      alias="Asia/Saigon Asia/Ho_Chi_Minh" iana="Asia/Ho_Chi_Minh"/>

Toàn bộ cơ chế nằm trong hai thuộc tính đó. Cái tên đầu tiên trong alias là định danh chuẩn tắc của CLDR, và nó là Asia/Saigon. Thuộc tính iana riêng biệt ghi nhận rằng IANA không đồng ý và đặt Asia/Ho_Chi_Minh làm tên chính.

CLDR biết về việc đổi tên. Họ chọn không đi theo, vì định danh chuẩn tắc là khóa và sự ổn định của khóa mới là điều cốt yếu: CLDR đã dùng Asia/Saigon từ lúc bắt đầu, và đổi nó về sau sẽ làm hỏng mọi thứ đã lưu dưới tên cũ. IANA quyết ngược lại, với lý do tên hiện tại phải luôn đúng. Hai tổ chức, hai định nghĩa “chuẩn tắc”, cùng một độ lệch bảy giờ.

Thuộc tính iana đó chỉ xuất hiện khi hai bên bất đồng, nên bản thân file tự nó đã là tài liệu. Đúng 19 trong 469 mục có thuộc tính này, và 19 mục đó chính là nơi một trình duyệt đi theo CLDR và dữ liệu IANA hiện hành gọi cùng một nơi bằng hai cái tên khác nhau:

Chuẩn tắc theo CLDRTên chính theo IANAĐịa điểm
Asia/SaigonAsia/Ho_Chi_MinhViệt Nam
Asia/CalcuttaAsia/KolkataẤn Độ
Europe/KievEurope/KyivUkraine
Asia/RangoonAsia/YangonMyanmar
Asia/KatmanduAsia/KathmanduNepal
America/Buenos_AiresAmerica/Argentina/Buenos_AiresArgentina
America/CordobaAmerica/Argentina/CordobaArgentina
America/CatamarcaAmerica/Argentina/CatamarcaArgentina
America/JujuyAmerica/Argentina/JujuyArgentina
America/MendozaAmerica/Argentina/MendozaArgentina
America/IndianapolisAmerica/Indiana/IndianapolisHoa Kỳ
America/LouisvilleAmerica/Kentucky/LouisvilleHoa Kỳ
America/Coral_HarbourAmerica/AtikokanCanada
America/GodthabAmerica/NuukGreenland
Atlantic/FaeroeAtlantic/FaroeQuần đảo Faroe
Africa/AsmeraAfrica/AsmaraEritrea
Pacific/EnderburyPacific/KantonKiribati
Pacific/PonapePacific/PohnpeiMicronesia
Pacific/TrukPacific/ChuukMicronesia

Dhaka là trường hợp đối chứng. Mục của nó ghi alias="Asia/Dhaka Asia/Dacca" mà không có thuộc tính iana, vì tên chuẩn tắc của CLDR đã trùng với của IANA — và đúng như vậy, không trình duyệt nào trả về Asia/Dacca cho bạn.

Mười ba quốc gia, và hình dạng danh sách nói lên một điều. Bảy trong mười chín là sắp xếp lại chứ không phải đổi tên: tzdb chuyển năm thành phố Argentina xuống dưới America/Argentina/, hai thành phố Mỹ xuống dưới bang của chúng, còn CLDR vẫn trỏ vào các tên phẳng cũ. Chỉ vài trường hợp — Saigon, Calcutta, Kiev, Rangoon — mới là những lần đổi tên mang tính chính trị mà người ta vẫn tưởng đây là chuyện của chúng. Hai trong số đó nằm ở Hoa Kỳ, điều thường làm bất ngờ những ai vẫn xếp chuyện này vào ngăn “vấn đề với múi giờ của người khác”.

Ở mọi nơi khác, hai tổ chức đồng thuận và chẳng có gì trong đây lộ ra cả.

Phần 1 xác lập được điều gì

Bốn điều để mang theo:

  1. Asia/Saigon là một bí danh, không phải một múi giờ. Không có gì bị xóa; chỉ là một symlink 11 byte thôi không còn được cài đặt.
  2. Máy nào có sẵn những bí danh nào là một quyết định đóng gói, và Debian đã đổi nó vào tháng 8/2023 — với một changelog nêu đích danh các database SQL có nhận biết múi giờ là ví dụ cho trường hợp có thể cần cài lại gói legacy.
  3. CLDR và IANA hiện bất đồng về việc trong hai cái tên thì cái nào là chuẩn tắc, ở 19 múi giờ, và không danh sách nào có dấu hiệu nhích về phía bên kia.
  4. Định danh múi giờ của IANA mang tính biên tập và sửa được, và không có gì trong tài liệu của tzdb hứa rằng chúng sẽ mãi là khóa ổn định. Định danh chuẩn tắc của CLDR đọc lên như một canh bạc ngược lại — ưu tiên cái tên cũ một khi nó đã được dùng làm khóa — và đó là cách giải thích tốt nhất tôi có cho việc hai danh sách phân ly, chứ không phải một chính sách mà dự án nào tuyên bố theo từng thành phố.

Gộp lại, bốn điều đó nói lên một chuyện khó chịu: một cái tên múi giờ không phải một giá trị, nó là một lần tra cứu vào một cơ sở dữ liệu, mà lại có nhiều hơn một cơ sở dữ liệu. Một chuỗi phân giải được trên máy này không được bảo đảm sẽ phân giải được trên máy kế tiếp, và bản thân chuỗi đó chẳng nói cho bạn biết là máy nào.

Chưa có gì hỏng cả. Nó hỏng ở phần 2, nơi một giá trị đi qua bốn hệ thống mà mỗi hệ thống tra cứu trên một bản sao khác nhau.