处理日期和时间数据--日期和时间函数
本节介绍一些对日期和时间数据类型进行操作的函数,包括GETDATE、CURRENT_TIMESTAP、GETUTCDATE、SYSDATETIME、SYSUTCDATETIME、SYSDATETIMEOFFSET、CAST、CONVERT、SWITCHOFFSET、TODATETIMEOFFSET、DATEADD、DATEDIFF、DATEPART、YEAR、MONTH、DAY,以及DATENAME。注意,SYSDATETIME、SYSUTCDATETIME、SYSDATETIMEOFFSET、SWITCHOFFSET,以及TODATETIMEOFFSET是SQL Server 2008中新增的,其他几个函数在SQL Server 2008之前的版本中也可以使用。不过,SQL Server 2008对原有的几个函数进行了改进,以支持新的日期和时间数据类型,以及新的日期和时间组成部分。
日期和时间函数
以下几个不带参数的函数可以返回SQL Server实例所在系统的当前日期和时间:GETDATE、CURRENT_TIMESTAMP、GETUTCDATE、SYSDATETIME、SYSUTCDATETIME,以及SYSDATETIMEOFFSET。下表列举了这些函数的一些信息。
函数 |
返回类型 |
描述 |
是否是SQL Server 2008新加的 |
GETDATE |
DATETIME |
当前日期和时间 |
否 |
CURRENT_TIMESTAMP |
DATETIME |
与GETDATE相同,而且是ANSI SQL |
否 |
GETUTCDATE |
DATETIME |
以UTC格式表示的当前日期和时间 |
否 |
SYSDATETIME |
DATETIME2 |
当前日期和时间 |
是 |
SYSUTCDATETIME |
DATETIME2 |
以UTC格式表示的当前日期和时间 |
是 |
SYSDATETIMEOFFSET |
DATETIMEOFFSET |
当前日期和时间,包含时区偏移量 |
是 |
注意,除了ANSI函数CURRENT_TIMESTAMP以外,对于不需要参数的函数,在调用它们时都必须多加一对空的圆括号。此外,因为CURRENT_TIMESTAMP和GETDATE返回的内容相同,但前者是标准SQL,所以推荐优先选用CURRENT_TIMESTAMP。我们应该尽量遵循一条实践原则:当完成同样的事情有多种选择,而且它们之间在功能和性能上都没有区别,但只有一个是标准SQL,其他都不是时,我们应该偏向选择使用标准SQL。
以下代码演示了取得当前日期和时间函数的用法:
1 SELECT
2 GETDATE() AS [GETDATE],
3 CURRENT_TIMESTAMP AS [CURRENT_TIMESTAMP],
4 GETUTCDATE() AS [GETUTCDATE],
5 SYSDATETIME() AS [SYSDATETIME],
6 SYSUTCDATETIME() AS [SYSUTCDATETIME],
7 SYSDATETIMEOFFSET() AS [SYSDATETIMEOFFSET];
或许你会发现,SQL Server 2008中的函数都不是只返回当前系统日期或只返回当前系统时间。不过,通过把CURRENT_TIMESTAMP或SYSDATETIME转换为DATE或TIME,可以容易地做到这一点,如下所示:
1 SELECT
2 CAST(SYSDATETIME() AS DATE) AS [Current_date],
3 CAST(SYSDATETIME() AS TIME) AS [Current_time];
CAST和CONVERT函数
CAST和CONVERT函数用于转换值的数据类型。
语法
CAST(value AS datatype)
CONVERT(datatype,value [,style_number])
这两个函数都可以将输入的值转换为指定的数据类型。在一些情况下,还能用CONVERT提供的第三个参数来指定转换的样式。例如,当把字符串转换成日期和时间数据类型(或者进行反向转换)时,style样式值可以指定字符串的格式。例如,样式值101表示'MM/DD/YYYY',而103则表示'DD/MM/YYYY'。有关样式值和它们各自含义的完整列表,可以在SQL Server联机丛书的“CAST和CONVERT”一节中找到相关的内容。当把字符串转换成某些日期和时间数据类型时,一些字符串格式是依赖于语言的。这里推荐要么使用一种独立于语言的格式,要么使用CONVERT函数,显示地指定要用的样式值。这样,无论登录时用的语言是什么,SQL Server对代码的解释方式都是一样的。
注意,CAST是ANSI标准SQL,而CONVERT不是;所以,除非需要使用样式值,否则推荐优先使用CAST函数,以保证代码尽可能与标准兼容。
以下代码把字符串文字'20090212'转换成一个DATE数据类型的值,其实只能提取其当前的系统日期:
1 SELECT CAST('20090212' AS DATE);
以下代码把当前系统日期和时间值转换成一个TIME数据类型的值,其实只能提取其当前的系统时间:
1 SELECT CAST(SYSDATETIME() AS TIME);
还记得DATE和TIME是SQL Server 2008新引入的数据类型吧。前面介绍过,如果在SQL Server 2008之前的版本中只想用日期或时间,就必须把DATETIME或SMALLDATETIME值中不相关的部分设置为“0”。换句话说,要只使用日期,就得把时间部分设置为午夜;要只使用时间,就得把日期设置为基础日期1900年1月1日。稍后将会介绍把给定的日期和时间值(比如CURRENT_TIMESTAMP)中不相关的部分设置为0的技巧。
以下代码用样式值112('YYYYMMDD'),把当前日期和时间值转换为CHAR(8):
1 SELECT CONVERT(CHAR(8),CURRENT_TIMESTAMP,112);
例如,如果当前日期是2009年2月12日,这一代码将返回'20090212'。记住该样式是语言无关的,所以当用代码把结果再转换回DATETIME类型时,得到的当前日期的时间部分将是午夜:
1 SELECT CAST(CONVERT(CHAR(8),CURRENT_TIMESTAMP,112) AS DATETIME);
类似地,要把日期部分设置为基础日期,可以先用样式114值('hh:mm:ss.nnn')把当前日期和时间值转换为CHAR(12):
1 SELECT CONVERT(CHAR(12),CURRENT_TIMESTAMP,114);
当用代码把结果再转换回DATETIME时,得到的当前的日期部分将是基础日期:
1 SELECT CAST(CONVERT(CHAR(12),CURRENT_TIMESTAMP,114) AS DATETIME);
SWITCHOFFSET函数
SWITCHOFFSET函数可以按指定的时区对输入的DATETIMEOFFSET值进行调整。
语法
SWITCHOFFSET(datetimeoffset_value,time_zone)
例如,以下代码将当前系统时间的datetimeoffset值按时区-05:00进行调整:
1 SELECT SWITCHOFFSET(SYSDATETIMEOFFSET(),'-05:00');
如果当前系统的datetimeoffset值是February 12,2009 10:00:00.0000000 -08:00,这段代码将返回以下值:February 12,2009 13:00:00.0000000 -05:00。
而以下代码则将当前的datetimeoffset值调整为UTC时间:
1 SELECT SWITCHOFFSET(SYSDATETIMEOFFSET(),'+00:00');
假设当前的datetimeoffset值为前面提到的那个值,该代码将返回以下值:
February 12,2009 18:00:00.0000000 +00:00。
TODATETIMEOFFSET函数
语法
TODATETIMEOFFSET(date_and_time_value,time_zone)
这个函数与SWITCHOFFSET函数的区别有两点。首先,它可以接受的输入不限于datetimeoffset值,而是支持任何日期和时间数据类型。其次,它不是根据输入值的原始值和指定的时区之间的差值来调整时间,而只是简单地用指定的时区将输入的日期和时间值作为datetimeoffset值返回。例如,如果当前系统的datetimeoffset值是February 12,2009 10:00:00.0000000 -08:00,运行以下代码:
1 SELECT TODATETIMEOFFSET(SYSDATETIMEOFFSET(),'-05:00');
会得到以下值:February 12,2009 10:00:00.0000000 -05:00。还记得前面的SWITCHOFFSET函数返回值是February 12,2009 13:00:00.0000000 -05:00吧,因为它是根据输入的时区(-08:00)和指定的时区(-05:00)之间的时区差来调整时间的。
如前所述,TODATETIMEOFFSET函数可以支持任何日期和时间数据类型作为输入。例如,以下代码以当前系统日期和时间值作为输入,将其更改为时区是-05:00的datetimeoffset值:
1 SELECT TODATETIMEOFFSET(SYSDATETIME(),'-05:00');
DATEADD函数
DATEADD函数可以将指定日期的部分作为单位,为输入的日期和时间值增加指定的数量。
语法
DATEADD(part,n,dt_val)
日期部分的有效值包括year、quarter、month、dayofyear、day、week、weekday、hour、minute、second、millisecond、microsecond,以及nanosecond。最后两个是SQL Server 2008新增加的。也可以按缩写格式来指定这些时间部分,例如用yy代替year。要了解相关的细节,请参考SQL Server联机丛书。
该函数返回值的类型与输入的日期和时间值的类型相同。如果输入的是一个字符串文字,输出的则是DATETIME。
例如,以下代码为“2009年2月12日”增加1年:
1 SELECT DATEADD(year,1,'20090212');
DATEDIFF函数
DATEDIFF返回两个日期和时间值之间相差的指定部分的计数。
语法
DATEDIFF(part,dt_val1,dt_val2)
例如,以下代码返回两个值之间相差的天数:
1 SELECT DATEADD(day,DATEDIFF(day,'20010101',CURRENT_TIMESTAMP),'20010101');
在SQL Server 2008之前的版本中,可以用以下代码将当前系统日期和时间值中的时间部分设置为午夜:
1 SELECT DATEADD(month,DATEDIFF(month,'20010101',CURRENT_TIMESTAMP),'20010101');
这段代码首先用DATEDIFF函数计算一个锚点(anchor)日期的午夜值(在这个例子中是'20010101')与当前日期和时间之间相差的总天数(也称为不同的diff值)。接着,再用DATEADD函数为锚点日期增加上一步得到的diff天。这样就可以得到当前系统日期在午夜的时间值。
有趣的是,如果在这个表达式中用month(月)取代day(天)来作为计数单位,并确保使用的锚点日期是某个月的第1天(如我们这个例子所示),最后得到的结果将是当前月份的第1天:
1 SELECT DATEADD(month,DATEDIFF(month,'20010101',CURRENT_TIMESTAMP),'20010101');
类似地,用year(年)作为计数单位,并用某年的第1天作为锚点日期,最后得到的将是当前年的第1天。
如果想要得到当前月或当前年的最后一天,只要简单地把锚点日期修改为月或年的最后1天。例如,以下表达式返回当前月份的最后1天:
1 SELECT DATEADD(MONTH,DATEDIFF(month,'19991231',CURRENT_TIMESTAMP),'19991231');
DATEPART函数
DATEPART函数返回一个表示给定日期和时间值的指定部分的整数。
语法
DATEPART(part,dt_val)
part参数的有效值包括year、quarter、month、dayofyear、day、week、weekday、hour、minute、second、millisecond、microsecond、nanosecond、TZoffset,以及ISO_WEEK。最后4个part参数值是SQL Server 2008中新增的。如前所述,日期和时间部分的名称也可以使用缩写格式,如用yy代替year、用mm代替month、用dd代替day,等等。作为例子,以下代码返回输入值的月份部分:
1 SELECT DATEPART(month,'20090212');
这一代码将返回整数2.
YEAR、MONTH和DAY函数
YEAR、MONTH,以及DAY函数是DATEPART函数的简略版本,它们分别返回一个代表输入日期和时间值中年、月、日部分的整数。
语法
YEAR(dt_val)
MONTH(dt_val)
DAY(dt_val)
例如,以下代码提取出输入值的日、月、年部分:
1 SELECT DAY('20090212') AS theday,
2 MONTH('20090212') AS themonth,
3 YEAR('20090212') AS theyear;
DATENAME函数
DATENAME函数返回一个表示给定日期和时间值的指定部分的字符串。
语法
DATENAME(part,dt_val)
这个函数与DATEPART类似,它们的part输入参数的有效值都是相同的。不过,DATENAME返回的是代表请求部分的名字,而不是数字。例如,以下代码返回给定输入值的月份的名称:
1 SELECT DATENAME(month,'20090212');
回想一下,对于同样的输入,前面的DATEPART返回的是整数2。而DATENAME返回的是月份的名称,该名称是依赖于语言的。如果当前会话的语言是某种英语,函数调用的返回值将是'February'。如果请求的部分没有名称,只是一个数字值(比如年份),则DATENAME函数将它的数字值作为字符串而返回。例如,以下代码返回'2009':
1 SELECT DATENAME(year,'20090212');
ISDATE函数
ISDATE接受一个字符串作为输入,如果能把这个字符串转换为日期和时间数据类型的值,则返回值1;如果不能,则返回值0。
语法
ISDATE(string)
例如,以下代码返回1:
1 SELECT ISDATE('20090212');
而以下代码则返回0:
1 SELECT ISDATE('20090230');