Cơ Chế Lưu Trữ Ngày Giờ Bên Trong SQL Server

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 byte
  • n = 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 nanosecond
  • DateTime2(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

Thẻ: SQL-Server-Storage DateTime-Internals Binary-Conversion

Đăng vào ngày 29 tháng 6 lúc 12:16