2 điểm bởi GN⁺ 2024-12-27 | 1 bình luận | Chia sẻ qua WhatsApp
  • POSIX time/Unix time thường được gọi là số giây kể từ 1970-01-01 00:00:00, nhưng trên thực tế đó là giá trị dựa trên UTC nhưng bỏ qua giây nhuận, nên lệch với số giây thực sự đã trôi qua
  • Tính đến 2024-12-25 18:51:26 UTC, POSIX time là 1735152686, còn số giây thực sự đã trôi qua kể từ epoch là 1735152713 giây, chênh lệch 27 giây
  • Khi định nghĩa seconds since the Epoch, IEEE 1003.1 luôn tính một ngày là 86.400 giây, và phụ lục của chuẩn cũng bỏ qua 14 giây nhuận được thêm từ năm 1970 để thuận tiện cho tính toán và khả năng tương thích
  • UTC thêm giây nhuận để giảm sai khác với ngày Mặt Trời; khi đó POSIX time có thể nhảy lùi, dẫn đến các sự cố như trên Linux, Qantas và Cloudflare DNS
  • Để đo khoảng thời gian trên một máy, CLOCK_MONOTONIC hoặc CLOCK_BOOTTIME phù hợp hơn; nếu cần khớp với POSIX timestamp thì nên cân nhắc leap smear hoặc chuyển đổi POSIX↔TAI

POSIX time không phải là số giây thực sự đã trôi qua

  • JavaScript Date, GNU coreutils, Linux time(2), Go time.Unix, MySQL datetime, Ruby Time, Cassandra timestamp v.v. thường xử lý POSIX time như thể đó là số giây kể từ Unix epoch
  • Nhưng cách diễn đạt này không hoàn toàn khớp với trực giác thông thường
    • Mốc thời gian ví dụ: 2024-12-25 18:51:26 UTC
    • POSIX time: 1735152686
    • Số giây thực sự đã trôi qua kể từ POSIX epoch: 1735152713
    • Chênh lệch: 27 giây
  • Sự khác biệt này xuất hiện vì POSIX time được suy ra từ IEEE 1003.1UTC, nhưng lại giả định mọi ngày đều có đúng 86.400 giây
  • Định nghĩa seconds since the Epoch trong chuẩn tính giá trị bằng tm_sec, tm_min, tm_hour, tm_yday, tm_year, và không định nghĩa quan hệ với các giá trị nhỏ hơn năm 1970 hoặc giá trị âm
  • Độ dài thực tế của một ngày không phải lúc nào cũng là 86.400 giây và thay đổi theo thời gian
    • Các nhà thiên văn học định kỳ công bố giây nhuận để ngày UTC không lệch quá xa khỏi ngày Mặt Trời
    • Kết quả là POSIX time có thể nhảy lùi vài năm một lần
    • Và trong tương lai cũng có thể nhảy tiến
  • Giây nhuận đã từng gây ra sự cố thực tế

Sự thỏa hiệp của chuẩn và các lựa chọn thay thế trong thực tế

  • Phụ lục B của IEEE 1003 tóm tắt rằng tại thời điểm ban hành chuẩn đã có 14 giây nhuận được thêm sau 1970-01-01, nhưng các giây này bị bỏ qua để việc tính toán đơn giản hơn và đảm bảo khả năng tương thích
  • Chuẩn giả định giá trị “time” của hầu hết hệ thống tăng liên tục, và chọn hướng giá trị này vẫn phải tăng ngay cả trong lúc có giây nhuận
    • Đồng thời cũng giả định rằng phần lớn hệ thống không theo dõi giây nhuận hoặc có thể không được đồng bộ với chuẩn thời gian chuẩn
    • Vì vậy, nó không yêu cầu seconds since the Epoch nhất thiết phải biểu diễn chính xác số giây giữa thời điểm tham chiếu và epoch
    • Chỉ cần ứng dụng có thể xử lý giá trị này như số giây kể từ epoch, còn mức độ chính xác cần thiết là việc của nhà cung cấp hệ thống và quản trị viên
  • Trong các ứng dụng phân tán, sự kiện được đồng bộ bằng timestamp nên cách diễn giải nhất quán có thể trở nên quan trọng
    • Việc tích lũy giây nhuận là không thể dự đoán trước
    • Số giây nhuận kể từ epoch có khả năng còn tiếp tục tăng
    • Chuẩn quan tâm nhiều hơn đến việc đồng bộ thời gian giữa các ứng dụng trong các khoảng thời gian ngắn theo góc nhìn thiên văn
  • Trên thực tế, hệ thống thường vẫn hoạt động dù thời gian hơi lệch, nhưng vì giây nhuận hiếm gặp và trực giác tuyến tính của “số giây kể từ epoch” rất mạnh, nên có thể tích lũy nhiều lỗi chưa bị phát hiện
  • Các lựa chọn thay thế theo từng tình huống gồm có
    • Nếu chỉ cần tính duration giữa hai sự kiện trên một máy, dùng CLOCK_MONOTONIC, hoặc tốt hơn nữa là CLOCK_BOOTTIME
    • Nếu không cần trao đổi timestamp với các hệ thống khác giả định POSIX time, hãy dùng TAI, GPS, LORAN
    • Nếu cần khớp tương đối với các hệ thống POSIX timestamp, dùng leap smear để dàn đều giây nhuận trên một khoảng thời gian dài hơn
    • Có thể chuyển đổi giữa POSIX và TAI bằng thư viện như qntm no t-a-i
  • Các nỗ lực nhằm bãi bỏ giây nhuận đang được tiến hành và được kỳ vọng sẽ thành hiện thực trước năm 2035
    • Điều này sẽ đòi hỏi thêm công việc để đưa bảng chuyển đổi vào mọi thứ đang phụ thuộc vào giả định một ngày có 86.400 giây
    • Đối với các thời điểm sau năm 2035, những câu hỏi như “có bao nhiêu giây giữa hai thời điểm” có thể trở nên đơn giản hơn rất nhiều

1 bình luận

 
GN⁺ 2024-12-27
Ý kiến trên Hacker News
  • Tôi vừa đọc xong tiểu thuyết khoa học viễn tưởng năm 2000 của Vernor Vinge, A Deepness in the Sky; đây là một cuốn sách tuyệt vời với một nhắc đến bất ngờ về số giây kể từ epoch (seconds since the epoch)
    Bắt đầu bằng câu “Hãy nhìn cách Traders đo thời gian…”, sách mô tả rằng Qeng Ho đếm theo giây từ khoảnh khắc nhân loại lần đầu đặt chân lên Mặt Trăng của Old Earth, nhưng nếu xem kỹ hơn thì mốc bắt đầu thực ra muộn hơn khoảng 15 triệu giây, tức giây 0 của một trong những hệ điều hành máy tính thời kỳ đầu của loài người

    • Cá nhân tôi xem cuốn này là một trong những cuốn yêu thích nhất mọi thời, và tôi thật sự thích cách nó dùng các tham chiếu phần mềm tinh tế
      Nếu muốn thêm kiểu “khoa học máy tính trong vũ trụ”, tôi khuyên đọc series Bobiverse; nếu muốn đào sâu hơn về “con người + mô phỏng + máy tính” thì nên đọc Permutation City
  • Mỗi lần đọc về đo thời gian, tôi đều học được điều gì đó mới. Trước đây tôi nghĩ Unix time là cách đơn giản nhất để theo dõi thời gian nếu chỉ tính đến rollover, và tôi có biết về giây nhuận, nhưng chưa từng nghĩ nó cũng áp dụng ở đây
    Tôi cũng đã đọc liên kết “UTC, GPS, LORAN and TAI”, và thấy sự tương phản ở việc giờ GPS không phản ánh giây nhuận khá thú vị

    • Nói rằng một việc xảy ra trước/sau bao nhiêu giây thì đơn giản. Phần khó là gán thời điểm đó vào ngày tháng trên lịch
    • Rốt cuộc tôi thấy TAI là đơn giản nhất, còn các định dạng khác chỉ nên được chuyển đổi từ TAI khi cần, chẳng hạn để hiển thị hoặc để tương tác liên hệ thống
  • Tôi không thích lắm kế hoạch “đang có nỗ lực loại bỏ giây nhuận trước năm 2035”
    Điểm cốt lõi của UTC là lệch khỏi TAI một số nguyên giây và xấp xỉ giờ Mặt Trời trung bình (MST). Nếu không còn theo dõi MST nữa thì nên chuyển hẳn sang TAI
    Nếu cứ để UTC trôi xa khỏi MST, ta rơi vào một trạng thái nửa vời: vẫn phải xử lý các giây nhuận trong quá khứ, nhưng chúng không còn mục đích nữa

    • Tôi đồng ý rằng việc rời khỏi MST có chi phí lớn hơn lợi ích thu được
      Tuy vậy đề xuất này không hoàn toàn vô nghĩa. Mục đích là không thay đổi cách quản lý thời gian UTC hiện có, đồng thời khiến chênh lệch giữa hai timestamp sau năm 2035 trở thành đúng số giây vật lý
      Dù vậy, vì MST vốn đã là một chức năng của UTC, việc loại bỏ nó trông khá buồn cười
    • Trong một thế giới lý tưởng, hệ thống máy tính lẽ ra nên dùng TAI để theo dõi thời gian, rồi dùng cơ sở dữ liệu TZ để chuyển đổi sang UTC hoặc giờ địa phương
      Nhưng trong thực tế, nhiều hệ thống đã chọn sai, đặc biệt UNIX là nguyên nhân lớn nhất. Lựa chọn đó đã ăn sâu vào vô số hệ thống và quy định, nên “cứ chuyển sang TAI” gần như là bất khả thi
      Vì vậy, diễn giải lại UTC thành “TAI mới” sẽ dễ hơn. Tôi sẽ không ngạc nhiên nếu một ngày nào đó UTC cũ xuất hiện trở lại dưới một cái tên khác
    • Không hề có một thực thể TAI riêng biệt. TAI là thứ nhận được bằng cách bắt đầu từ UTC rồi trừ đi số giây nhuận liên quan. TAI không được duy trì như một đại lượng chuẩn độc lập
      Ở hầu hết hoặc tất cả các quốc gia, giờ dân dụng dựa trên UTC. Sẽ không có chuyện vặn đồng hồ toàn thế giới lùi khoảng 30 giây chỉ vì nó thuần túy hơn một chút
      Giờ GPS cũng có offset với TAI nhưng chẳng ai quá bận tâm. Unix epoch cũng vậy; miễn là kết quả nhất quán thì đủ
    • Cách hack này đúng nghĩa là tầm thường. Mỗi tháng một lần kiểm tra xem UTC # ET hay không; nếu khác, tạo một file tên Leap_Second. Hằng tháng kiểm tra xem file này có tồn tại không; nếu có thì xóa nó, cộng 1 vào giá trị trong file Leap_Seconds, rồi tạo một bản sao lưu tên LSSE
      “You are not expected to understand this.” Đây là cách duy trì cả hai hệ thống. Nếu muốn cũng có thể làm bằng hash hoặc bảng tra cứu
  • Một điểm quan trọng nữa là UTC epoch hiện đại là ngày 1 tháng 1 năm 1972. Trước đó UTC dùng độ dài giây khác với TAI
    Cuối năm 1971, ở giai đoạn chuyển tiếp, có một bước nhảy bất quy tắc cuối cùng chính xác 0,107758 giây TAI; các bước thời gian nhỏ và các điều chỉnh tần số của UTC hoặc TAI trong giai đoạn 1958–1971 được căn sao cho tổng đúng bằng 10 giây. Vì vậy 1972-01-01 00:00:00 UTC chính xác là 1972-01-01 00:00:10 TAI, và từ đó về sau chênh lệch là số nguyên giây
    Đồng thời, tốc độ tick của UTC trở nên đúng bằng TAI, và UTC bắt đầu theo dõi UT1 thay vì UT2. Do đó Unix time trong các năm 1970 và 1971 không khớp với thời gian UTC thực tế của giai đoạn đó
    https://en.wikipedia.org/wiki/Coordinated_Universal_Time#His...
    https://en.wikipedia.org/wiki/Unix_time#UTC_basis

    • Vì điều này, có những người hiện còn sống không thể biết và sau này cũng không thể biết tuổi chính xác của mình tính bằng giây
      Ngay cả khi giả định thời gian trên giấy khai sinh chính xác đến từng giây cũng vậy. Lý do là trong một phần cuộc đời của họ, giá trị được coi là “độ dài của 1 giây” khá khác so với 1 giây mà ngày nay chúng ta thường nghĩ đến
      Ở đây giây có nghĩa là giây dựa trên tần số chuyển tiếp siêu tinh tế của trạng thái cơ bản không bị nhiễu loạn của nguyên tử cesium-133, 9.192.631.770/s
  • Gần đây tôi viết một đoạn mã cho một sàn giao dịch, hệ thống đó chạy trên VAX, hay chính xác là trên OpenVMS, và epoch của nó là ngày 17 tháng 11 năm 1858
    Đây là lần đầu tiên trong sự nghiệp tôi thấy một epoch không phải Unix; may là trong phần mã đang dùng, nó đã được trừu tượng hóa thành Unix epoch

    • Epoch năm 1858 có vẻ bắt nguồn từ Julian Day, lịch chuẩn trong thiên văn học. Trong đó ngày 0 là năm 4713 TCN
      https://www.slac.stanford.edu/~rkj/crazytime.txt
      Để nhét các ngày này vào bộ nhớ máy tính thập niên 1950, người ta offset lịch đi 2,4 triệu ngày, kết quả là ngày 0 trở thành 17 tháng 11 năm 1858
    • Cũng có một giai thoại cũ của Microsoft về xung đột giữa epoch của Excel là ngày 1 tháng 1 năm 1900 và của Basic là ngày 31 tháng 12 năm 1899
      https://www.joelonsoftware.com/2006/06/16/my-first-billg-rev...
    • Một hệ thống tính toán phổ biến khác đáng biết là Windows epoch, vào ngày 1 tháng 1 năm 1601
    • Classic MacOS, hệ thống tệp HFS của Apple (cũng được dùng trong OS X), và PalmOS đều có epoch là ngày 1 tháng 1 năm 1904
      API macOS/Swift Foundation NSDate.timeIntervalSinceReferenceDate dùng ngày 1 tháng 1 năm 2001 làm epoch
      Wikipedia cũng có một danh sách hữu ích: https://en.wikipedia.org/wiki/Epoch_(computing)#Notable_epoc...
    • PostgreSQL nội bộ dùng epoch 2000-01-01 để lưu timestamp
  • Có những thời điểm không thể biểu diễn bằng timestamp POSIX, và có những timestamp POSIX không tương ứng với thời gian thực

    • Tôi thắc mắc timestamp POSIX nào không tương ứng với thời gian thực. Hay ý là trường hợp trong tương lai có giây nhuận âm?
    • Chuyện này vốn luôn là vậy. Trong Unix time, thời gian trước năm 1970 không được định nghĩa
    • Dù vậy, ít nhất không có một timestamp POSIX nào tương ứng với từ hai thời điểm thực trở lên. Vẫn tốt hơn một cách biểu diễn mà mọi người dùng cho mọi thứ
    • Không phải vậy
      Nói thế giống như nói có những thời điểm không có năm ISO 8601. Mọi thời điểm đều có năm, chỉ là một số năm dài hơn những năm khác mà thôi
      Nếu ngồi nhìn https://time.is/UTC, thời gian sẽ tăng đơn điệu, thỉnh thoảng chỉ có một giây dài hơn một chút. Ví dụ như dài hơn khoảng 0,001% trong 24 giờ
  • Khi lưu ngày vào cơ sở dữ liệu, tôi luôn lưu dưới dạng Unix epoch time, và không ghi thông tin múi giờ trong trường ngày. Nếu có yêu cầu cần biết múi giờ thì lưu riêng
    Tôi tự hỏi liệu thay vào đó có nên lưu timestamp ở định dạng TAI, rồi dùng hàm chuyển đổi sang UTC khi cần, để có thể xử lý các hiệu chỉnh liên quan đến Trái Đất khi cần không
    Tôi biết múi giờ là một bãi mìn, nhưng bản thân nó cũng là cấu trúc do con người tạo ra, với ranh giới múi giờ thay đổi theo thời gian. Có lẽ nên cố định vào thời gian tuyệt đối rồi khi cần thì render sang định dạng giờ địa phương mong muốn

    • Đúng vậy. TAI hoặc một định dạng tương tự là cách hợp lý duy nhất để theo dõi thời gian “hệ thống”, và các hệ thống cấp cao hơn nên chuyển nó sang thời gian con người nhìn thấy
      Việc điều chỉnh giây nhuận nên diễn ra ở cùng chỗ với chuyển đổi múi giờ. Tiếc là Unix đã chuẩn hóa cái sai, và việc migration thì khó
    • Phần lớn là không, và gần như luôn không. Hầu hết phần mềm được viết để che phủ/nuốt giây nhuận, và trên thực tế nó chỉ xảy ra ở tầng đồng bộ đồng hồ. Ví dụ chrony có triển khai leap smear
      Vì vậy mọi đồng hồ dù sao cũng được căn theo UTC. Bạn sẽ phải chuyển từ UTC sang TAI khi lưu, rồi chuyển ngược lại khi đọc, rất dễ thành một mớ hỗn độn
    • Về phần “không ghi thông tin múi giờ trong trường ngày”, thực tế rất ít cơ sở dữ liệu cho phép bảo toàn múi giờ trong cột timestamp
      Thông thường cơ sở dữ liệu hoặc không có khái niệm múi giờ cho timestamp đã lưu (SQL Server), hoặc cung cấp kiểu timestamp “nhận biết múi giờ” nhưng chuyển đầu vào sang UTC và bỏ múi giờ gốc (MySQL, Postgres)
      Theo tôi biết, chỉ Oracle mới có thể thực sự round-trip và bảo toàn múi giờ không phải local trong kiểu with time zone
    • Còn tùy hệ thống lưu cái gì. Hầu hết hệ thống không quan tâm chuyện lệch 1 giây vài năm một lần
      Trong một số phép tính, chênh lệch 1 giây là vấn đề lớn. Khi chọn thứ không phải định dạng phổ biến nhất, phải cẩn thận và cần có lý do chính đáng để đi lệch chuẩn. Chỉ riêng việc khác biệt thôi cũng có thể tạo ra chi phí lớn
    • Cứ dùng trường ngày-giờ native của cơ sở dữ liệu là được
  • Bài này làm tôi cảm giác như Giáng sinh bị phá hỏng. Chẳng có gì thiêng liêng nữa sao? Giây phải là số giây kể từ epoch chứ
    Tôi không hiểu tại sao phải bận tâm chuyện nó lệch một chút so với ngày Mặt Trời. Chẳng phải bộ chuyển đổi từ số giây kể từ epoch sang biểu diễn ngày tháng chịu trách nhiệm hiệu chỉnh là được sao?

    • Cách hiện tại thực ra chính là cách chúng ta muốn. 86400 giây = 1 ngày, và chúng ta vận hành với giả định nửa đêm UTC luôn là bội số của 86400
      Tôi không muốn mọi phần mềm phải hard-code việc đưa giây nhuận vào, xử lý smear, và mỗi khi có giây nhuận mới thì trong vòng một tháng lại đòi hỏi cách cập nhật
      Từ trước đến nay ta đã không phải lo hay nghĩ về nó, và sau này cũng không cần. Nó đang được xử lý theo cách đúng
  • Nên thay giây nhuận bằng tên lửa khổng lồ gắn ở xích đạo. Đừng chỉnh đồng hồ, hãy chỉnh hành tinh

    • Nếu tính toán sai khiến Trái Đất quay quá chậm hoặc quá nhanh thì chắc không còn vui lắm
      Trong truyền thống Hồi giáo cũng có đoạn về tận thế và Kẻ chống Chúa (Dajjal) kiểu chuyện như vậy thực sự xảy ra. “Ngày đầu tiên của Kẻ chống Chúa sẽ như một năm, ngày thứ hai như một tháng, ngày thứ ba như một tuần”; nhiều người hiểu điều đó theo nghĩa đen, tức là như một sự kiện vũ trụ nơi vòng quay của Trái Đất thực sự chậm lại và cuối cùng đảo chiều, khiến Mặt Trời mọc ở phía tây. Đó là dấu hiệu cuối cùng của ngày tận thế nhân loại
  • Có vẻ như dù vì giây nhuận mà epoch trở thành một thời điểm xa hơn 29 giây so với điều date +%s ngụ ý thì cũng chẳng có gì đáng bận tâm
    Việc tất cả mọi người thống nhất về một con số N nào đó biểu thị thời gian hiện tại quan trọng hơn nhiều. Con số -29 giây giả định không ảnh hưởng đến thế giới thực. Chẳng lẽ lại chạy routine ngắm tên lửa vào một mục tiêu của 30 năm trước sao
    Tôi ủng hộ việc bãi bỏ giây nhuận, nhưng không nghĩ việc nhấn mạnh sự không nhất quán về thời gian là hữu ích. Dù xét kỹ thì điều đó đúng đi nữa

    • Có thể hình dung tình huống tính thời lượng của một sự kiện ngắn bằng thời điểm bắt đầu/kết thúc. Nếu khoảng đó vắt qua một giây nhuận, tùy cách xử lý timestamp mà thời lượng có thể khác đi khá nhiều
      Điều quan trọng hơn là ảnh hưởng đến tương lai. Việc timestamp trong quá khứ có thể lệch vài giây so với phép tính đơn giản “hiện tại - N giây” phần lớn chỉ là một sự thật thú vị, nhưng việc tại một thời điểm nào đó trong tương lai mọi đồng hồ có thể lại phải dịch chuyển thêm 1 giây thì quan trọng hơn. Có nhiều trường hợp thực tế đòi hỏi khá nhiều công sức để tính đến điều này
    • Với một số thứ thì nó quan trọng. Nếu không có các giây nhuận giả định đó, chẳng hạn vị trí của Mặt Trời vào giữa trưa địa phương sẽ lệch đi 29 giây