在sql server的內部儲存中,日期和時間不是以字串的形式儲存的,而是使用整數來儲存的。使用特定的格式來區分日期部分和時間部分的偏移量,並通過基準日期和基準時間來還原真實的資料。
一,datetime的內部儲存
sql server儲存引擎把datetime型別儲存為2個int32型別,共8個位元組,第乙個int32 整數(前4個位元組)儲存的是日期相對於基準日期(1900-01-01)的偏移量。基準日期是1900-01-01,當前4 位元組為0 時,表示的日期是1程式設計客棧900 年1 月1 日。第二個int32整數(後4個位元組)儲存的是午夜(00:00:00.000)之後的時鐘滴答數,每個滴答為1⁄300秒,精確度為3.33毫秒(0.00333秒,3.33ms),因此,datetime能夠表示的時間,可能會存在乙個滴答的時間誤差。
datetime的內部儲存格式,用十六進製制表示是:ddddtttt
舉個例子,對於如下的日期和時間,把datetime型別轉換為大小為8個位元組的16進製制,每兩個數字對應1個位元組:
declare @dt datetime = '2015-05-07 10:05:23.187'
select convert(varbinary(8), @dt) as date_time_binary
--output 0x0000a49100a6463c
1,拆分出date和time
把時間的二進位制格式中的位元組拆分成兩部分:前4個位元組表示date,後4個位元組表示time,得出的結果如下:
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,通過偏移量還原日期和時間
通過基準時間和偏移量,把整數還原為原始的日期和時間:
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
二,datetime2的內部儲存
datetime2(n)資料型別儲存日期和時間,它是datetime的公升級版本,由於小數秒n的精度可以自主設定,其儲存大小(storage size)不固定,datetime2(n)占用的儲存空間和小數秒的精度之間的關係是:
1,二進位制逆序
在探索datetime2(n)的內部儲存之前,先了解一下位元組儲存的「小端」格式和「大端」格式:
舉個例子,假如記憶體位址左邊是地位,右邊是高位,對於數字275,使用兩個位元組來儲存:
datetime2(n)的內部儲存格式使用的是小端格式,這種格式適合cpu的運算。
2,datetime2的儲存格式
datetime2(n)的內部儲存格式是:
tui是由精度來控制的,每乙個tui是10的n次方之一秒,也就是:
為了便於運算,把datetime2(n) 的位元組流逆序排列:前3個位元組表示的是天數,最後乙個位元組表示的是精度,中間餘下的位元組表示的tui的數量。例如,對於 datetime2(7)按照位元組流逆序處理之後,儲存空間是9個位元組:前三個位元組是儲存的從基準日期0001-01-01之後的多少天,最後一位是精度n,中間的5個位元組表示從子夜開始有多少個tui。
2,把datetime2轉換為二進位制儲存
把datetime2轉換為二進位制儲存,並作逆序處理,datetime2(3)的精度為3,儲存空間是8個位元組,後三個位元組記錄從基準日期0001-01-01之後的多少天,程式設計客棧前3個位元組表示從子夜開始有多少個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
把二進位制值拆分成datetime2(3)的各個組成成分:
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,利用偏移量和基準還原原始值
有了偏移量,就可以在基準日期和時間之上加上偏移量來獲得原始值:
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
參考文件:
what is the sql server 2008 datetime2 internal structure?
how to get sql server dates and times horribly wrong
總結本文標題: sql server 日期和時間的內部儲存過程
本文位址: /shujuku/mssql/290640.html
SQL Server的日期和時間型別
sql server使用 date 表示日期,time表示時間,使用datetime和datetime2表示日期和時間。1,秒的精度 秒的精度是指tsql使用多少位小數,datetime資料型別秒的精度是3,datetime2和time可以控制秒的精度,語法是datetime2 n 和time n ...
SQL Server 日期和時間函式
1 常用日期方法 下面的getdate 2006 11 08 13 37 56.233 1 datename datepart date 返回表示指定日期的指定日期部分的字串。datepart詳見下面的列表.select datename day,getdate 返回8 2 datepart dat...
SQL Server 日期和時間函式
1 常用日期方法 下面的getdate 2006 11 08 13 37 56.233 1 datename datepart date 返回表示指定日期的指定日期部分的字串。datepart詳見下面的列表.select datename day,getdate 返回8 2 datepart dat...