SQL Server không lưu trữ giá trị ngày giờ dưới dạng chuỗi mà sử dụng số nguyên với cơ chế đặc biệt. Hệ thống chia thành hai thành phần: phần ngày tính theo khoảng cách từ mốc chuẩn, phần thời gian tính theo đơn vị thời gian cơ bản (TUI) kể từ nửa đêm.
Lưu trữ kiểu DateTime
Kiểu dữ liệu DateTime chiếm 8 byte (2 số nguyên 32-bit). Byte đầu tiên (4 byte) biểu diễn số ngày chênh lệch so với mốc chuẩn 1900-01-01. Byte thứ hai lưu số đơn vị thời gian kể từ 00:00:00.000, với mỗi đơn vị bằng 1/300 giây (độ chính xác 3.33ms).
Ví dụ chuyển đổi giá trị ngày giờ thành dạng nhị phân:
DECLARE @thoiGian DATETIME = '2023-10-15 14:30:45.670'
SELECT CONVERT(BINARY(8), @thoiGian) AS MaHoaByte
-- Kết quả: 0x0000A9B3010C2A7E
Tách thành phần ngày và thời gian:
WITH DuLieu AS (
SELECT
CONVERT(BINARY(8), @thoiGian) AS ToanBo,
SUBSTRING(CONVERT(BINARY(8), @thoiGian), 1, 4) AS NgayByte,
SUBSTRING(CONVERT(BINARY(8), @thoiGian), 5, 4) AS GioByte
)
SELECT
NgayByte,
CONVERT(INT, NgayByte) AS NgaySo,
GioByte,
CONVERT(INT, GioByte) AS GioSo
FROM DuLieu
Phục hồi giá trị gốc từ số nguyên:
DECLARE @MocThoiGian TIME = '00:00:00.000'
DECLARE @MocNgay DATE = '1900-01-01'
SELECT
DATEADD(DAY, 46027, @MocNgay) AS NgayGoc,
DATEADD(MS, 13504567 * 10 / 3, @MocThoiGian) AS GioGoc
Lưu trữ kiểu DateTime2
Kiểu DateTime2(n) có kích thước lưu trữ thay đổi theo độ chính xác n (0-7):
n < 3: 7 byte (1 byte độ chính xác + 6 byte dữ liệu)n = 3-4: 8 byten = 5-7: 9 byte
Hệ thống sử dụng định dạng little-endian (byte thấp ở địa chỉ thấp) cho cả thành phần ngày và thời gian. Thành phần thời gian được tính bằng TUI - khoảng thời gian cơ bản phụ thuộc vào n:
DateTime2(7): 1 TUI = 100 nanosecondDateTime2(3): 1 TUI = 1 millisecond
Ví dụ xử lý giá trị DateTime2(4):
DECLARE @thoiGianChiTiet DATETIME2(4) = '2023-10-15 14:30:45.6789'
DECLARE @maHoa VARBINARY(8) = CONVERT(VARBINARY(8), @thoiGianChiTiet)
SELECT
@maHoa AS MaGoc,
REVERSE(@maHoa) AS MaDaoNguoc
Tách cấu trúc lưu trữ sau khi đảo ngược thứ tự byte:
WITH XuLy AS (
SELECT REVERSE(@maHoa) AS MaDao
)
SELECT
SUBSTRING(MaDao, 1, 3) AS NgayByte,
CONVERT(INT, SUBSTRING(MaDao, 1, 3)) AS SoNgay,
SUBSTRING(MaDao, 4, 5) AS GioByte,
CONVERT(BIGINT, SUBSTRING(MaDao, 4, 5)) AS SoTUI,
CONVERT(TINYINT, SUBSTRING(MaDao, 8, 1)) AS DoChinhXac
FROM XuLy
Phục hồi giá trị gốc từ TUI và mốc chuẩn 0001-01-01:
SELECT
DATEADD(DAY, 738808, CAST('0001-01-01' AS DATE)) AS NgayPhucHoi,
DATEADD(MICROSECOND, 52245678, CAST('00:00:00.000000' AS TIME(4))) AS GioPhucHoi