SQL Server stored deep inside the date and time

In the internal storage of SQL Server, the date and time is not stored as a string, but using integers to store. To distinguish between the date portion and an offset portion of the time, and to restore the true reference date data and the reference time by using a specific format.

A, DateTime internal storage

Storing the SQL Server engine DateTime type is stored as an int32 2, a total of 8 bytes, a first integer int32 (first four bytes) stored with respect to the reference date is the date (1900-01-01) offset the amount. The reference date is 1900-01-01, the current 4-byte 0, represents the date January 1, 1900. Int32 second integer (4 bytes) is stored the number of clock ticks after midnight (00: 00.000: 00), each tick is 1/300 seconds, with an accuracy of 3.33 milliseconds (0.00333 seconds, 3.33ms) Therefore, DateTime time can be expressed, there may be a time error of a tick.

DateTime internal storage format, hexadecimal is: DDDDTTTT

  • DDDD: occupies 2 bytes and indicates the offset of the reference date
  • TTTT: occupies two bytes, always represents the number of ticks after midnight

For example, for the following dates and times, converting DateTime type size is 8 byte hexadecimal number corresponding to each of two 1 byte:

declare @dt datetime = '2015-05-07 10:05:23.187'
select convert(varbinary(8), @dt) as date_time_binary
--output 0x0000A49100A6463C

1, the date and time resolution

The time in binary format byte split into two parts: the first four bytes date, the 4 bytes time, the results are as follows:

declare @dt datetime = '2015-05-07 10:05:23.187'

select substring(convert(varbinary(8), @dt), 1, 4) as date_binary,
   cast(substring(convert(varbinary(8), @dt), 1, 4) as int) as date_int,
   substring(convert(varbinary(8), @dt), 5, 4) as time_binary,
   cast(substring(convert(varbinary(8), @dt), 5, 4) as int) as time_int;

 2, the date and time by reducing the offset

By the reference time and the offset integer to revert to the original date and time:

declare @Time time='00:00:00.000'
declare @Date date='1900-01-01'

select dateadd(day, 42129, @Date) as originl_date
    , dateadd(ms,10896956*10/3, @Time) as original_time

Two, DateTime2 internal storage

DateTime2 (n) data types stores date and time, it is an upgraded version of DateTime, since the accuracy of the fractional seconds of n may be independently set storage size (Storage Size) is not fixed, DateTime2 (n) storage space and fractional seconds the relationship between the accuracy is:

  • The first byte storage precision DateTime2 (n) stored internally n, the subsequent byte to store values ​​of date and time.
  • When the accuracy of the fractional second n <3, the total storage space 1B (precision) +6 B (data);
  • When n is fractional seconds precision of 3 - 4, the total storage space 1B (precision) + 7B (data);
  • When n is fractional seconds precision 5--7, the total storage space 1B (precision) + 8B (data), the maximum fractional seconds precision is 7, the default value is 7;

1, binary reverse

Before exploring DateTime2 (n) of internal memory, first look at the byte stored "little endian" format and "big-endian" format:

  • Big-endian format: refers to the lower-bit data stored in the high address memory, whereas the data of the high, the low address is stored in memory; and
  • Little-endian format: refers to the lower-bit data stored in the lower memory address, while the high order data stored in the memory of the address.

For example, if the status of the memory address on the left, the right is high, the digital 275, using two bytes to store:

  • If a big-endian format: byte sequence is 0x0113
  • If little endian: byte sequence is 0x1301

Used DateTime2 (n) of the internal storage format is little-endian format, which is suitable for CPU operations.

2, DateTime2 storage format

DateTime2 (n) of the internal storage format is:

  • The first byte of the stored precision n,
  • After three byte records from the number of days after the reference date 0001-01-01, little endian.
  • The number of bytes remaining after the intermediate recording unit after midnight time interval (time unit interval, TUI), the little endian.

TUI is controlled by the precision of every n-th power of 10 TUI is one second, namely:

  • For DateTime2 (7), TUI is 100ns;
  • For DateTime2 (6), TUI is 1 microsecond (= 1000ns);
  • For DateTime2 (5), TUI is 10 microseconds;
  • For DateTime2 (4), TUI is 100 microseconds;
  • For DateTime2 (3), TUI is 1ms (1 ms = 1000 sec);

For ease of operation, the DateTime2 (n) byte stream in reverse order: the first three bytes represent the number of days, the last byte is the precision of the middle number of the remaining bytes of the TUI. For example, for DateTime2 (7) after the byte stream in accordance with the reversing of the storage space is 9 bytes: The first three bytes are stored in the number of days from the reference date 0001-01-01 after the last one is the precision n the middle five bytes from the start the number of TUI midnight.

2, is converted to the binary storage DateTime2

DateTime2 convert the binary storage, and for the reverse process, DateTime2 (3) an accuracy of 3, storage space is 8 bytes, three bytes recorded after the number of days from the reference date 0001-01-01 after before 3 bytes indicate how many start from midnight TUI.

declare @dt datetime2(3)='2015-05-07 10:05:23.187'
declare @dt_bi varbinary(max)=convert(varbinary(max), @dt) 
select @dt_bi as date_time_binary
    ,convert(varbinary(max),reverse(@dt_bi)) as reverse_binary

The binary value resolved into DateTime2 (3) of the respective components:

declare @dt datetime2(3)='2015-05-07 10:05:23.187'
declare @dt_bi varbinary(max)=convert(varbinary(max), @dt) 
declare @dt_bi_littleEnd varbinary(max)
select @dt_bi_littleEnd=convert(varbinary(max),reverse(@dt_bi))

select substring(convert(varbinary(8), @dt_bi_littleEnd), 1, 3) as date_binary,
   cast(substring(convert(varbinary(8), @dt_bi_littleEnd), 1, 3) as int) as date_int,
   substring(convert(varbinary(8), @dt_bi_littleEnd), 4, 4) as time_binary,
   cast(substring(convert(varbinary(8), @dt_bi_littleEnd), 4, 4) as int) as time_int,
   substring(convert(varbinary(8), @dt_bi_littleEnd), 8, 1) as precision_binary,
   cast(substring(convert(varbinary(8), @dt_bi_littleEnd), 8, 1) as int) as precision_int;

3, using an offset value and restores the original reference

With the offset, the offset may be added to the original values ​​obtained on the reference date and time:

declare @Time time='00:00:00.000'
declare @Date date='0001-01-01'

select dateadd(day, 735724, @Date) as originl_date
    , dateadd(ms,36323187, @Time) as original_time

 

 

 

Reference documents:

What is the SQL Server 2008 DateTime2 Internal Structure?

How to Get SQL Server Dates and Times Horribly Wrong

Guess you like

Origin www.cnblogs.com/ljhdo/p/10208322.html