SQL Server 日期和時間類型


在Microsoft SQL Server的類型系統中,使用 date 表示日期類型,使用time表示時間類型,使用DateTime和DateTime2表示日期和時間的組合,DateTime2是DateTime的升級版本,這些數據類型占用的存儲空間各不相同;當存儲大量數據時,合理的選擇小數秒的精度,能夠節省數據的占用空間。

當表示國際時間時,存在本地時間和UTC時間之別,同一個時刻,UTC時間是固定的,而本地時間由於時區的差異而不相同。如果一個數據實體的時間字段對時區敏感,那么可以使用DateTimeOffset數據類型,該類型不僅包含本地的日期和時間,還包括本地的時區,用戶能夠根據本地的時間和時區推算出UTC時間,公式是:UTC時間=本地時間+時區偏移。

小數秒的精度(fractional seconds precision)是指使用多少位小數表示一秒,DateTime2、Time和DataTimeOffset可以控制小數秒的精度,語法是DateTime2(n)、time(n),DataTimeOffset(n),n是小數秒的精度,n的取值范圍是0-7,默認值是7,即使用7位小數表示1s,能夠表示的最小精確時間(Accuracy)是100ns。DateTime數據類型的最小精確時間是3.33毫秒(0.00333秒),其精確度不高,建議在產品環境中,使用DateTime2(n)來代替DateTime類型。

一,日期和時間類型

DateTime2(n)表示日期和時間,Date只表示日期,Time(n)只表示時間,最后簡單介紹DateTime類型。

1,DateTime2數據類型

DateTime2(n)數據類型存儲日期和時間,它是DateTime的升級版本,由於小數秒n的精度可以自主設置,其存儲大小(Storage Size)不固定,DateTime2(n)占用的存儲空間和小數秒的精度之間的關系是:

  • DateTime2(n)內部存儲的第一個字節存儲精度n,后續的字節用於存儲值。
  • 當小數秒的精度 n < 3 時,存儲空間是1B(精度)+ B(數據);
  • 當小數秒的精度 n 是 3 - 4 時,存儲空間是1B(精度)+ 7B(數據);
  • 當小數秒的精度 n 是 5 - 7 時,存儲空間是1B(精度)+ 8B(數據),最大的小數秒精度是7,默認值是7;

DateTime2可以表示比DateTime更精確的時間,默認的數據格式是yyyy-MM-dd hh:mm:ss.nnnnnnn,DateTime2 秒默認的精度是7,即用7位小數表示一秒的精度。

datetime2 [ (fractional seconds precision) ]

下面兩種聲明DateTime2變量的方式是等價的:

declare @dt2 datetime2(7)
declare @dt2 datetime2

為DateTime2類型的變量賦值,需要使用SysDateTime()和SysUTCDateTime(),這兩個函數返回值的類型是DateTime2(7)。

declare @dt2 datetime2
set @dt2=SYSDATETIME()

3,Date數據類型

Date數據類型只存儲日期,不存儲時間,僅需要3B的存儲空間,默認的數據格式是yyyy-MM-dd,支持的日期范圍從0001-01-01到9999-12-31

可以使用日期字符串,getdate()等函數為Date類型的變量賦值:

declare @d date
set @d='2015-07-02'
set @d=getdate()
set @d=SYSDATETIME()

4,Time類型

Time(n)數據類型只存儲時間,不存儲日期,需要5B的存儲空間。Time(n)小數秒精度n的默認值是7,默認的數據格式是hh:mm:ss.nnnnnnn

time [ (fractional second precision) ]

推薦使用時間字符串和sysdatetime()函數為Time類型的變量賦值,不推薦使用GetDate()函數,GetDate()函數返回的是DateTime類型,時間部分的小數位精度是3,如果對時間的精度要求高,請使用時間字符串和sysdatetime()函數為Time類型的變量賦值。

--declare @t time(7)
DECLARE @t time
set @t='13:48:43.2840467'
set @t=SYSDATETIME()

--not recommend
set @t=GETDATE()

4,DateTime數據類型

DateTime數據類型存儲日期和時間,其存儲空間是固定的8個字節,默認的數據格式是yyyy-MM-dd hh:mm:ss.nnn,表示從1753年1月1日到9999年12月31日的日期和時間數據,精確度為3.33毫秒(0.00333秒),也就是說,DateTime表示的日期范圍從公元1753年1月1日00:00:00.000 到9999年12月31日23:59:59.997 ,精確到3.33毫秒。

在DateTime使用的8個字節中,實際上,SQL Server用兩個4 字節的整數內部存儲 datetime 數據類型的值。第一個 4 字節存儲基准日期(即 1900 年 1 月 1 日)之前或之后的天數。基准日期是系統參考日期,不允許出現早於 1753 年 1 月 1 日的 date 值。當第一個4 字節為0 時,表示的日期是1900 年1 月1 日;在基准日期之前的日期,第一個4字節的值是負數,在基准日期之后的日期,第一個4字節的值是正數。另外一個 4 字節存儲以10/3 毫秒數所代表的每天的時間。

declare @dt datetime

使用GetDate()和GetUTCDate()為DateTime類型的變量賦值,這兩個函數返回值的類型是DateTime

declare @dt datetime
set @dt=getdate()

鑒於DateTime的精確度(精確度為3.3毫秒)沒有DateTime2(n)高,並且占用的存儲空間也比DateTime2(n)高,所以,建議在產品環境中使用DateTime2(n)來代替DateTime類型。

5,SamllDateTime 數據類型

SamllDateTime數據類型的存儲空間是固定的4bytes,由Date 和時間構成,Date的取值范圍從 1900-01-01 到 2079-06-06,時間部分是24小時制,秒數通常是00,取值范圍從 00:00:00 到 23:59:00。由於SmallDateTime會把時間近似到分鍾,秒數通常是0,且不符ANSI和 ISO 8601,因此,在實際的開發中使用的比較少,建議使用time, date, datetime2 和 datetimeoffset來用於新的開發程序中。

select cast(getdate() as smalldatetime) as now_sdt, cast(getdate() as datetime) as now_dt

二,DateTimeOffset類型

DateTimeOffset(n)數據類型由三部分構成:date、time和 offset(時區偏移),包含了日期、時間和時區數據,其日期和時間使用是本地時間。在本地時間的基礎上,使用時區偏移量(offset)來計算UTC時間,因此,DateTimeOffset(n)可以同時表示本地時間和UTC時間,默認的顯示文本是:YYYY-MM-DD hh:mm:ss[.nnnnnnn] [{+|-}hh:mm],默認值是1900-01-01 00:00:00 00:00。

DateTimeOffset(n)能夠表示的日期、時間和時區范圍是:

  • 表示的日期范圍是:0001-01-01 到 9999-12-31,
  • 表示的時間范圍是:00:00:00 到 23:59:59.9999999,表示的時間精度是100ns,
  • 表示的時區范圍是:-14:00 到 +14:00

小數秒的精度會影響變量占用的存儲空間的大小:

  • 當小數秒的精度n是 0-2 時,存儲大小是8B
  • 當小數秒的精度n是 3-4 時,存儲大小是9B
  • 當小數秒的精度n是 5-7 時,存儲大小是10B,小數秒的默認精度是7

時區偏移的格式為:[+|-] hh:mm,hh 表示的小時范圍是00-14,mm 表示的分鍾范圍是00-59,把DateTimeOffset時間中的UTC時間 和 時區偏移量 進行算術運算,可以得到本地時間。

1,返回本地時間的DateTimeOffset

返回本地的時間和時區,本地時間是2018-08-29 11:11:29.5765832,本地所在的時區是東八區:

SELECT SYSDATETIMEOFFSET ( )

2,把DateTime2時間轉換為DateTimeOffset時間

向DateTime2時間中添加時區信息:

TODATETIMEOFFSET ( expression , time_zone )  

參數注釋:

  • expression:是DateTime2類型的值,
  • time_zone:是時區的偏移量,格式是 [+|-] hh:mm

 例如,使用SYSDATETIME得到本地的DateTime2,添加時區(東八區),得到的包含時區信息的DateTimeOffset:

SELECT TODATETIMEOFFSET(SYSDATETIME(),'+08:00'),SYSDATETIMEOFFSET()

3,切換時區

把DateTimeOffset類型的數據切換到指定的時區,在轉換過程中,UTC時間是固定的,依據固定的UTC時間,切換到特定時區的本地時間:

SWITCHOFFSET ( DATETIMEOFFSET, time_zone )  

參數注釋:

  • DATETIMEOFFSET:DateTimeOffset(n)類型的變量
  • time_zone:指定的目標時區數據,格式是  [+|-] hh:mm

例如,把本地時間的時區東八區切換到東七區:

DECLARE @remote DATETIMEOFFSET 
DECLARE @local DATETIMEOFFSET
SET @local = SYSDATETIMEOFFSET()
SET @remote = SWITCHOFFSET (@local, '+07:00')
SELECT @remote AS remote_time,@local AS local_time

可以看到,東7區的時間比東8區的時間晚一個小時。

4,丟棄時區信息

DateTime2表示的是本地時間,DateTimeOffset表示的是本地時間和本地的時區,如果數據不需要考慮時區信息,那么可以直接把DateTimeOffset時間賦值給DateTime2時,SQL Server執行隱式轉換,把時區信息丟棄,只把本地時間賦值給DateTime2:

DECLARE @datetimeoffset DATETIMEOFFSET(4) 
DECLARE @datetime2 DATETIME2(3)=@datetimeoffset;  

SET @datetimeoffset= '2012-10-25 12:24:32.1277 +01:00'
SET @datetime2=@datetimeoffset

SELECT @datetimeoffset AS '@datetimeoffset', @datetime2 AS '@datetime2';

三,日期和時間類型占用的字節數

DataLength能過返回任意數據類型的變量所占用的字節數量,從下圖中可以看到,datetime占用的存儲空間太大,精度不高,datetime2完勝datetime,在產品環境中,推薦使用datetime2:

declare @dt1 datetime
declare @dt2 datetime2(2)
declare @dt3 datetime2(4)

set @dt1=getdate()
set @dt2=getdate()
set @dt3=SYSDATETIME()

select DATALENGTH(@dt1),DATALENGTH(@dt2),DATALENGTH(@dt3),@dt1,@dt2,@dt3

如果對time的要求不是很高,保留2位毫秒,使用datetime2(2),比其他類型節省存儲空間。

四,SQL Server 的本地時間和UTC時間

本地時間:世界的每個地區都有自己的本地時間,整個地球分為二十四時區,每個時區都有自己的本地時間。

UTC時間:在國際無線電通信中,為統一而普遍使用一個標准時間,稱為通用協調時(UTC, Universal Time Coordinated)。UTC時間和英國倫敦的本地時間相同。UTC時間在世界各地都是相同的,但是不同的時區,本地時間各不相同。根據UTC時間和所在的時區,能夠計算出本地時間。

1,獲取本地時間和UTC時間

在SQL Sever中,GetDate()返回的是本地時間,GetUTCDate()返回的是UTC時間,返回的數據類型是DateTime;SysDateTime() 返回的是本地時間,SysUTCDateTime() 返回的是UTC時間,返回的數據類型是DateTime2(7)。

在不同的時區,UTC時間相同,但是本地時間不同。本地時間是Server上顯示的系統時間,在OS中變更時區(time zone),能夠修改本地時間和GetDate()的返回值。本地時間是根據UTC時間和OS設置的時區推導出來的。

結論:GetDate() 和SysDateTime() 返回的是本地Server的Date和Time,這個值跟SQL  Server實例本地主機的OS有關,跟OS顯示的時間是相同的。 

2,SQL Agent 執行Job的時間

在SQL Server Agent中使用的時間是本地時間,Job的執行時間是本地時間。

五,對DateDiff()函數的正確理解

此函數返回在開始日期和結束日期之間對於datepart邊界的計數:

DATEDIFF ( datepart , startdate , enddate )  

當我們指定datepart 時,無論是年、月、小時還是分鍾,數據庫引擎比較的數據都不會超出該部分。 因此,如果我們指定月份,則引擎只比較年份和月份,但不會做進一步的比較。這些值可能相隔僅一秒鍾,但是引擎關心的只是年份和月份。

舉個例子,下面的腳本返回的值都是1,雖然兩個時間只差100納秒,但是當比較的datepart邊界大於100ns時,都只會返回1個datepart單位。

SELECT DATEDIFF(year,       '2005-12-31 23:59:59.9999999', '2006-01-01 00:00:00.0000000')
    , DATEDIFF(quarter,     '2005-12-31 23:59:59.9999999', '2006-01-01 00:00:00.0000000')
    , DATEDIFF(month,       '2005-12-31 23:59:59.9999999', '2006-01-01 00:00:00.0000000')
    , DATEDIFF(dayofyear,   '2005-12-31 23:59:59.9999999', '2006-01-01 00:00:00.0000000')
    , DATEDIFF(day,         '2005-12-31 23:59:59.9999999', '2006-01-01 00:00:00.0000000')
    , DATEDIFF(week,        '2005-12-31 23:59:59.9999999', '2006-01-01 00:00:00.0000000')
    , DATEDIFF(hour,        '2005-12-31 23:59:59.9999999', '2006-01-01 00:00:00.0000000')
    , DATEDIFF(minute,      '2005-12-31 23:59:59.9999999', '2006-01-01 00:00:00.0000000')
    , DATEDIFF(second,      '2005-12-31 23:59:59.9999999', '2006-01-01 00:00:00.0000000')
    , DATEDIFF(millisecond, '2005-12-31 23:59:59.9999999', '2006-01-01 00:00:00.0000000')
    , DATEDIFF(microsecond, '2005-12-31 23:59:59.9999999', '2006-01-01 00:00:00.0000000');

六,12小時制和24小時制

十二小時制是大多數指針式鍾表顯示時間的方法,注意鍾面上數字沒有0,但有12,所以起點是12。24小時制的0:30,在鍾面上讀成12:30,再用AM表示上午,用PM表示下午。

 

對於凌晨12點,用12小時制表示是12:00 AM,用24小時制表示是00:00。

對於中午12點,用12小時制表示是12:00 PM,用24小時制表示是12:00。

對於凌晨30分,用12小時制表示是12:30 AM,用24小時制表示是00:30。

 

 

參考文檔:

Date and Time Data Types and Functions (Transact-SQL)

DATALENGTH (Transact-SQL)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM