對于開發人員來說,日期處理或許簡單,或許很難。結合自己過往的開發經驗并整合網上的例子,總結出一些日期相關的操作,供自己備用及為大家分享
一、日期類型:
對于SQL Server 2008 來說(因為2000甚至2005已經稍微有被淘汰的跡象,所以在此不作過多說明,加上自己工作使用的是2008R2。所以不保證08以前的能用),日期類型有:
注意:所有系統日期和時間值均得自運行 SQL Server 實例的計算機的操作系統。
每一種日期類型有其使用范圍,當然以剛好適用為最佳選擇,切記不要為了方便,什么都用datetime類型。從性能方面會有很大影響,舉個例子:
一個表,有1億行的數據,有10列日期型(對于一些歷史表來說這是完全有可能的)。如果全部使用datetime,那么光這部分的存儲空間就是:10*100000000*8字節/(1024*1024)≈7629M≈7.4G,當然,如果有這樣的需要,再大也還是要用的,假設其實業務上不需要那么精確(因為datetime是精確到0.00333秒),只需要精確到1分鐘即可,那么毫不猶豫使用smalldatetime,可以減少一半的空間,也就是大約3.7G。減少空間的好處有很多,比如備份及數據庫文件的大小可以減少,讓有限的預算做更多的事情。而且數據頁固定8KB,越少的體積單頁能存放的數據也就越多,查詢時要訪問的頁面就更少,緩解I/O壓力。同時對索引的使用也更有效,等等。
所以這里就能體現出“設計”的重要性。
二、日期函數:日期函數是處理日期的基礎,牢記日期函數能減少很多編程工作
精度較高的系統日期和時間函數
精確程度取決于運行 SQL Server 實例的計算機硬件和 Windows 版本。標注有:2012有效的是只有2012才出現的功能
精度較低的系統日期和時間函數
用來獲取日期和時間部分的函數
用來從部件中獲取日期和時間值的函數
用來獲取日期和時間差的函數
用來修改日期和時間值的函數
用來設置或獲取會話格式的函數
用來驗證日期和時間值的函數
三、日期操作詳解:
3.1、注意:SQL Server 將 0 解釋為 1900 年 1 月 1 日。
3.2、對于一些當前會話需要臨時改變日期設置時,可以使用SET關鍵字改變:
SET DATEFIRST { number | @number_var }:
將一周的第一天設置為從 1 到 7 的一個數字。7為默認的第一天,即周日。查看 SET DATEFIRST 的當前設置,請使用 @@DATEFIRST函數。注意此值是在運行時執行
SET DATEFORMAT{format|@format_var}:
設置用于解釋 date、smalldatetime、datetime、datetime2 和 datetimeoffset 字符串的月、日和年日期部分的順序。有效參數為 mdy、 dmy、 ymd、 ydm、 myd 和 dym默認值為 mdy。SETDATEFORMAT 將覆蓋 SETLANGUAGE 的隱式日期格式設置。
設置會話語言:雖然這里是語言,但是會影響日期的格式:
SET LANGUAGE Italian;
GO
SELECT @@DATEFIRST;
GO
SET LANGUAGE us_english;
GO
SELECT @@DATEFIRST;
3.3、常用函數操作:
四、常用日期處理案例:這是文章的重點,因為上面大部分內容都可以從聯機叢書中查到
給定某個日期,計算相關的值,目前我的工作中遇到比較多的就是這些,至于有些特殊歷法所需日期,目前沒遇到,所以沒總結:
代碼如下:
–定義給定的一天
DECLARE @Date DATETIME = GETDATE();
SELECT @Date AS ‘目前時間’
,DATEADD(DD,-1,@Date) AS ‘前一天’
,DATEADD(DD,1,@Date) AS ‘后一天’
/*月計算*/
,DATEADD(MONTH,DATEDIFF(MONTH,0,@Date),0) AS ‘月初’–在SQL Server中0 代表1900-01-01,通過月運算,保證日恒久為1號
,DATEADD(DD,-1,DATEADD(MONTH,1+DATEDIFF(MONTH,0,@Date),0)) AS ‘月末(精確到天)’–找到下月初再扣減1天,建議使用DATEADD而不要直接“-1”
,DATEADD(SS,-1,DATEADD(MONTH,1+DATEDIFF(MONTH,0,@Date),0)) AS ‘月末(精確到datetime的小數位)’
,DATEADD(MONTH,DATEDIFF(MONTH,0,@Date)-1,0) AS ‘上月第一天’
,DATEADD(DAY,-1,DATEADD(DAY,1-DATEPART(DAY,@Date),@Date)) AS ‘上月最后一天’
,DATEADD(MONTH,DATEDIFF(MONTH,0,@Date)+1,0) AS ‘下月第一天’
,DATEADD(DAY,-1,DATEADD(MONTH,2,DATEADD(DAY,1-DATEPART(DAY,@Date),@Date))) AS ‘下月最后一天’
/*周計算*/
,DATEADD(WEEKDAY,1-DATEPART(WEEKDAY,@Date),@Date) AS ‘本周第一天(周日)’–注意此處與@@datefirst的值有關
,DATEADD(WEEK,DATEDIFF(WEEK,-1,@Date),-1) AS ‘所在星期的星期日’–注意此處與@@datefirst的值有關
,DATEADD(DAY,2-DATEPART(WEEKDAY,@Date),@Date) AS ‘所在星期的第二天’–注意此處與@@datefirst的值有關,其他天數類推
,DATEADD(WEEK,-1,DATEADD(DAY,1-DATEPART(WEEKDAY,@Date),@Date)) AS ‘上個星期第一天(周日)’–注意此處與@@datefirst的值有關
,DATEADD(WEEK,1,DATEADD(DAY,1-DATEPART(WEEKDAY,@Date),@Date)) AS ‘下個星期第一天(星期日)’–注意此處與@@datefirst的值有關
,DATENAME(WEEKDAY,@Date) AS ‘本日是周幾’
,DATEPART(WEEKDAY,@Date) AS ‘本日是周幾’–返回值 1-星期日,2-星期一,3-星期二……7-星期六
/*年度計算*/
,DATEADD(YEAR,DATEDIFF(YEAR,0,@Date),0) AS ‘年初’
,DATEADD(YEAR,DATEDIFF(YEAR,-1,@Date),-1) AS ‘年末’
,DATEADD(YEAR,DATEDIFF(YEAR,-0,@Date)-1,0) AS ‘去年年初’
,DATEADD(YEAR,DATEDIFF(YEAR,-0,@Date),-1) AS ‘去年年末’
,DATEADD(YEAR,1+DATEDIFF(YEAR,0,@Date),0) AS ‘明年年初’
,DATEADD(YEAR,1+DATEDIFF(YEAR,-1,@Date),-1) AS ‘明年年末’
/*季度計算*/
,DATEADD(QUARTER,DATEDIFF(QUARTER,0,@Date),0) AS ‘本季季初’
,DATEADD(QUARTER,1+DATEDIFF(QUARTER,0,@Date),-1) AS ‘本季季末’
,DATEADD(QUARTER,DATEDIFF(QUARTER,0,@Date)-1,0) AS ‘上季季初’
,DATEADD(QUARTER,DATEDIFF(QUARTER,0,@Date),-1) AS ‘上季季末’
,DATEADD(QUARTER,1+DATEDIFF(QUARTER,0,@Date),0) AS ‘下季季初’
,DATEADD(QUARTER,2+DATEDIFF(QUARTER,0,@Date),-1) AS ‘下季季末’
五、建議:
創建時間維度表:在本人以前工作中,經常需要查詢時間范圍(精確到天),此時,可以創建一個表,每一行對應一天,然后其他列就是所需日期,比如季初季末、月初月末、年初年末甚至上年下年等。以供直接調用,并且就算存10年的數據,也就3000多條。有這樣需求的可以考慮使用。
六、速查手冊:日期往往要轉換成字符型再進行處理,所以這里貼出部分轉換結果
代碼如下:
Select CONVERT(varchar(100), GETDATE(), 0)–05 16 2006 10:57AM
Select CONVERT(varchar(100), GETDATE(), 1)–05/16/06
Select CONVERT(varchar(100), GETDATE(), 2)–06.05.16
Select CONVERT(varchar(100), GETDATE(), 3)–16/05/06
Select CONVERT(varchar(100), GETDATE(), 4)–16.05.06
Select CONVERT(varchar(100), GETDATE(), 5)–16-05-06
Select CONVERT(varchar(100), GETDATE(), 6)–16 05 06
Select CONVERT(varchar(100), GETDATE(), 7)–05 16, 06
Select CONVERT(varchar(100), GETDATE(), 8)–10:57:46
Select CONVERT(varchar(100), GETDATE(), 9)–05 16 200610:57:46:827AM
Select CONVERT(varchar(100), GETDATE(), 10)–05-16-06
Select CONVERT(varchar(100), GETDATE(), 11)–06/05/16
Select CONVERT(varchar(100), GETDATE(), 12)–060516
Select CONVERT(varchar(100), GETDATE(), 13)–16 05 2006 10:57:46:937
Select CONVERT(varchar(100), GETDATE(), 14)–10:57:46:967
Select CONVERT(varchar(100), GETDATE(), 20)–2006-05-16 10:57:47
Select CONVERT(varchar(100), GETDATE(), 21)–2006-05-16 10:57:47.157
Select CONVERT(varchar(100), GETDATE(), 22)–05/16/06 10:57:47 AM
Select CONVERT(varchar(100), GETDATE(), 23)–2006-05-16
Select CONVERT(varchar(100), GETDATE(), 24)–10:57:47
Select CONVERT(varchar(100), GETDATE(), 25)–2006-05-16 10:57:47.250
Select CONVERT(varchar(100), GETDATE(), 100)–05 16 2006 10:57AM
Select CONVERT(varchar(100), GETDATE(), 101)–05/16/2006
Select CONVERT(varchar(100), GETDATE(), 102)–2006.05.16
Select CONVERT(varchar(100), GETDATE(), 103)–16/05/2006
Select CONVERT(varchar(100), GETDATE(), 104)–16.05.2006
Select CONVERT(varchar(100), GETDATE(), 105)–16-05-2006
Select CONVERT(varchar(100), GETDATE(), 106)–16 05 2006
Select CONVERT(varchar(100), GETDATE(), 107)–05 16, 2006
Select CONVERT(varchar(100), GETDATE(), 108)–10:57:49
Select CONVERT(varchar(100), GETDATE(), 109)–05 16 200610:57:49:437AM
Select CONVERT(varchar(100), GETDATE(), 110)–05-16-2006
Select CONVERT(varchar(100), GETDATE(), 111)–2006/05/16
Select CONVERT(varchar(100), GETDATE(), 112)–20060516
Select CONVERT(varchar(100), GETDATE(), 113)–16 05 2006 10:57:49:513
Select CONVERT(varchar(100), GETDATE(), 114)–10:57:49:547
Select CONVERT(varchar(100), GETDATE(), 120)–2006-05-16 10:57:49
Select CONVERT(varchar(100), GETDATE(), 121)–2006-05-16 10:57:49.700
Select CONVERT(varchar(100), GETDATE(), 126)–2006-05-16T10:57:49.827
Select CONVERT(varchar(100), GETDATE(), 130)–18 ???? ?????? 142710:57:49:907AM
Select CONVERT(varchar(100), GETDATE(), 131)–18/04/142710:57:49:920AM