TIME
các giá trị luôn được lưu trữ trên 3 byte trong MySQL. Nhưng định dạng đã thay đổi trên phiên bản 5.6 .4
. Tôi nghi ngờ đây không phải là lần đầu tiên khi nó thay đổi. Nhưng sự thay đổi khác, nếu có, đã xảy ra từ lâu và không có bằng chứng công khai về điều đó. Lịch sử mã nguồn MySQL trên GitHub bắt đầu với phiên bản 5.5 (bản cam kết cũ nhất là từ tháng 5 năm 2008) nhưng sự thay đổi mà tôi đang tìm kiếm đã xảy ra vào khoảng năm 2001-2002 (MySQL 4 được đưa ra vào năm 2003)
Định dạng hiện tại, như được mô tả trong tài liệu, sử dụng 6 bit cho giây (các giá trị có thể có:0
thành 63
), 6 bit cho phút, 10 bit cho giờ (giá trị có thể:0
thành 1023
), 1 bit cho dấu (thêm các giá trị âm của các khoảng đã được đề cập) và 1 bit không được sử dụng và được gắn nhãn "dành riêng cho các phần mở rộng trong tương lai".
Nó được tối ưu hóa để làm việc với các thành phần thời gian (giờ, phút, giây) và không tốn nhiều dung lượng. Sử dụng định dạng này, bạn có thể lưu trữ các giá trị trong khoảng từ -1023:59:59
và +1023:59:59
. Tuy nhiên, MySQL giới hạn số giờ là 838
, có thể là để tương thích ngược với các ứng dụng đã được viết trước đó, khi tôi nghĩ đây là giới hạn.
Cho đến phiên bản 5.6.4, TIME
giá trị cũng được lưu trữ trên 3 byte và các thành phần được đóng gói dưới dạng days * 24 * 3600 + hours * 3600 + minutes * 60 + seconds
. Định dạng này được tối ưu hóa để làm việc với dấu thời gian (vì trên thực tế, nó là dấu thời gian). Sử dụng định dạng này, có thể lưu trữ các giá trị trong phạm vi khoảng -2330
thành +2330
giờ. Mặc dù có sẵn phạm vi giá trị lớn này, nhưng MySQL vẫn giới hạn các giá trị ở -838
thành +838
giờ.
Đã xảy ra lỗi # 11655
trên MySQL 4. Có thể trả về TIME
giá trị bên ngoài -838..+838
phạm vi sử dụng SELECT
lồng nhau các câu lệnh. Đó không phải là một tính năng mà là một lỗi và nó đã được sửa.
Lý do duy nhất để giới hạn các giá trị trong phạm vi này và để chủ động thay đổi bất kỳ đoạn mã nào tạo ra TIME
các giá trị bên ngoài nó là khả năng tương thích ngược.
Tôi nghi ngờ MySQL 3 đã sử dụng một định dạng khác, do cách dữ liệu được đóng gói, đã giới hạn các giá trị hợp lệ trong phạm vi -838..+838
giờ.
Bằng cách xem xét mã nguồn của MySQL Tôi đã tìm thấy công thức thú vị này:
#define TIME_MAX_VALUE (TIME_MAX_HOUR*10000 + TIME_MAX_MINUTE*100 + TIME_MAX_SECOND)
Hãy tạm thời bỏ qua MAX
một phần của các tên được sử dụng ở trên và hãy chỉ nhớ rằng TIME_MAX_MINUTE
và TIME_MAX_SECOND
là các số giữa 00
và 59
. Công thức chỉ nối giờ, phút và giây trong một số nguyên duy nhất. Ví dụ:giá trị 170:29:45
trở thành 1702945
.
Công thức này đặt ra câu hỏi sau:cho rằng TIME
giá trị được lưu trữ trên 3 byte có dấu, giá trị dương lớn nhất có thể được biểu diễn theo cách này là bao nhiêu?
Giá trị chúng tôi đang tìm kiếm là 0x7FFFFF
trong ký hiệu thập phân là 8388607
. Kể từ bốn chữ số cuối cùng (8607
) nên được đọc là phút (86
) và giây (07
) và giá trị hợp lệ tối đa của chúng là 59
, giá trị lớn nhất có thể được lưu trữ trên 3 byte có dấu bằng công thức ở trên là 8385959
. Mà, dưới dạng TIME
là +838:59:59
. Ta-da!
Đoán xem nào? Đoạn C
mã liệt kê ở trên được trích xuất từ cái này:
/* Limits for the TIME data type */
#define TIME_MAX_HOUR 838
#define TIME_MAX_MINUTE 59
#define TIME_MAX_SECOND 59
#define TIME_MAX_VALUE (TIME_MAX_HOUR*10000 + TIME_MAX_MINUTE*100 + TIME_MAX_SECOND)
Tôi chắc chắn đây là cách MySQL 3 sử dụng để giữ TIME
giá trị nội bộ. Định dạng này áp đặt giới hạn của phạm vi và yêu cầu tương thích ngược đối với các phiên bản tiếp theo đã phổ biến giới hạn cho thời của chúng ta.