ITPub博客

首页 > 数据库 > SQL Server > SQL Server - Date and Time Functions

SQL Server - Date and Time Functions

原创 SQL Server 作者:xxdxxdxxd 时间:2007-01-06 17:38:23 0 删除 编辑

In the previous articles in this series, I introduced you to aggregate and system-related functions. This article continues to explore various types of built-in functions. I will walk you through the most useful functions that fall into date and time, math, and text function categories.

Date and time functions enable a programmer to get the system date, as well as to manipulate the date and time values stored in the database. Because date and time functions are useful in many different circumstances, it's difficult to emphasize one particular usage as being more essential than the others.

[@more@]One complaint that you might hear is that SQL Server does not allow storing only the date or only the time—you must store both date and time in the same column if you use the DATETIME or SMALLDATETIME data type. Of course, you have the alternative of storing date values as strings, as in '1/1/2003'. Another alternative is to use the DATETIME data type and then use one of the date and time functions to retrieve only the needed portion (date or time) from the table.

One of my other InformIT.com articles covered the functions DATEPART and DATENAME in detail. DATEPART retrieves a portion of the date and time value (month, day, weekday, year, hour, minute, and so on) as an integer; DATENAME returns the character (for weekdays) or integer (for everything but weekdays) representation. DATEPART is deterministic in all cases except when it refers to weekdays. DATENAME, on the other hand is non-deterministic. (Please refer to my article "SQL Server: Determining Whether a Date is a Business Day" for an extensive coverage of these functions.)

The DAY(), MONTH(), and YEAR() functions are deterministic. Each of these functions accepts a single date value as a parameter and returns respective portions of the date as an integer. All three of these functions can be duplicated by retrieving the same portions of the date using the DATEPART function, as shown in the following example:

SELECT 
    DAY('1/1/2003'), 
    MONTH('1/1/2003'), 
    YEAR('1/1/2003'), 
    DATEPART(DAY, '1/1/2003'), 
    DATEPART(MONTH, '1/1/2003'),      
    DATEPART(YEAR, '1/1/2003')

Results:

----------- -----------  -----------  -----------  -----------  ----------- 
1           1            2003         1            1            2003

GETDATE() and GETUTCDATE() both return the current date and time. However, GETUTCDATE() returns the current Universal Time Coordinate (UTC) time, whereas GETDATE() returns the date and time on the computer where SQL Server is running. By the way, GETUTCDATE() does not have any magic power for determining the appropriate UTC time—it simply compares the time zone of SQL Server computer with the UTC time zone. Note that neither of these functions accepts parameters, and they are both non-deterministic. Here is an example:

SELECT 
    GETDATE() AS local_date, 
    GETUTCDATE() AS UTC_date

Results:

local_date                      UTC_date                       
-------------------------       ---------------------------- 
2003-01-26 14:32:35.713         2003-01-26 20:32:35.713

The DATEADD() and DATEDIFF() functions are both deterministic and can be very helpful in reporting applications (among other uses). The DATEADD() function adds a certain period of time to the existing date and time value. For instance, you can use the following query to determine the date six months from today:

SELECT DATEADD(MONTH, 6, GETDATE())AS '6_months_from_now'

Results:

6_months_from_now    
------------------------
2003-07-26 14:38:55.960

DATEADD() is also often used to determine which rows qualify for a particular report. Suppose that you want to see the report of all titles that have sold in the past nine years. you can effectively use DATEADD() with -9 as a parameter, as follows:

SELECT 
    DISTINCT 
    a.title_id, 
    title, 
    YEAR(ord_date) AS year_sold 
FROM sales a INNER JOIN titles b
ON a.title_id = b.title_id
WHERE 
ord_date > = DATEADD(YEAR, -9, GETDATE())

Results:

title_id   title                                          year_sold  
--------   ----------------------------------------       ----------- 
BU1032     The Busy Executive's Database Guide            1994
BU2075     You Can Combat Computer Stress!                2002
MC3021     The Gourmet Microwave                          1994
PS2091     Is Anger the Enemy?                            1994

The DATEDIFF() function accepts two DATETIME values and a date portion (minute, hour, day, month, and so on) as parameters. DATEDIFF() determines the difference between the two date values passed, expressed in the date portion specified. Notice that the start date should come before the end date if you want to see positive numbers in the result set. For instance, the following query determines the time difference between today and when each sale occurred in terms of months (the output is limited to the first five rows to save some room):

SELECT TOP 5
    ord_date,
    DATEDIFF(MONTH, ord_date, GETDATE()) AS no_of_months_since
FROM sales

Results:

ord_date                         no_of_months_since 
----------------------------     ----------------- 
1994-09-14 00:00:00.000          100
1994-09-13 00:00:00.000          100
1993-05-24 00:00:00.000          116
1994-09-13 00:00:00.000          100
1994-09-14 00:00:00.000          100

DATEDIFF() will work even if the end date is earlier than the start date—you will simply get negative values in the output. Keep in mind that DATEDIFF() returns an INTEGER; it does not calculate fractions for you. This might not seem relevant at first glance, but check out what happens when you compare the beginning and end of 2002 with the first day of 2003:

SELECT 
    DATEDIFF (YEAR, '1/1/2002', '1/1/2003'), 
    DATEDIFF (YEAR, '12/31/2002', '1/1/2003')

Results:

----------- ----------- 
1           1

So whether it is the first or last day of 2002, the difference between years is still 1, regardless of what you might expect.

通常,你需要获得当前日期和计算一些其他的日期,例如,你的程序可能需要判断一个月的第一天或者最后一天。你们大部分人大概都知道怎样把日期进行分割(年、月、日等),然后仅仅用分割出来的年、月、日等放在几个函数中计算出自己所需要的日期!在这篇文章里,我将告诉你如何使用DATEADDDATEDIFF函数来计算出在你的程序中可能你要用到的一些不同日期。
在使用本文中的例子之前,你必须注意以下的问题。大部分可能不是所有例子在不同的机器上执行的结果可能不一样,这完全由哪一天是一个星期的第一天这个设置决定。第一天(DATEFIRST)设定决定了你的系统使用哪一天作为一周的第一天。所有以下的例子都是以星期天作为一周的第一天来建立,也就是第一天设置为7。假如你的第一天设置不一样,你可能需要调整这些例子,使它和不同的第一天设置相符合。你可以通过@@DATEFIRST函数来检查第一天设置。

为了理解这些例子,我们先复习一下DATEDIFFDATEADD函数。DATEDIFF函数计算两个日期之间的小时、天、周、月、年等时间间隔总数。 DATEADD函数计算一个日期通过给时间间隔加减来获得一个新的日期。要了解更多的DATEDIFFDATEADD函数以及时间间隔可以阅读微软联机帮助。

使用DATEDIFFDATEADD函数来计算日期,和本来从当前日期转换到你需要的日期的考虑方法有点不同。你必须从时间间隔这个方面来考虑。比如, 从当前日期到你要得到的日期之间有多少时间间隔,或者,从今天到某一天(比如1900-1-1)之间有多少时间间隔,等等。理解怎样着眼于时间间隔有助于 你轻松的理解我的不同的日期计算例子。

一个月的第一天

第一个例子,我将告诉你如何从当前日期去这个月的最后一天。请注意:这个例子以及这篇文章中的其他例子都将只使用DATEDIFFDATEADD函数来计算我们想要的日期。每一个例子都将通过计算但前的时间间隔,然后进行加减来得到想要计算的日期。

这是计算一个月第一天的SQL 脚本:
SELECT DATEADD(mm, DATEDIFF(mm,0,getdate()), 0)

我们把这个语句分开来看看它是如何工作的。最核心的函数是getdate(),大部分人都知道这个是返回当前的日期和时间的函数。下一个执行的函数 DATEDIFF(mm,0,getdate())是计算当前日期和“1900-01-01 00:00:00.000”这个日期之间的月数。记住:时期和时间变量和毫秒一样是从“1900-01-01 00:00:00.000”开始计算的。这就是为什么你可以在DATEDIFF函数中指定第一个时间表达式为“0”。下一个函数是DATEADD,增加当 前日期到“1900-01-01”的月数。通过增加预定义的日期“1900-01-01”和当前日期的月数,我们可以获得这个月的第一天。另外,计算出来 的日期的时间部分将会是“00:00:00.000”

这个计算的技巧是先计算当前日期到“1900-01-01”的时间间隔数,然后把它加到“1900-01-01”上来获得特殊的日期,这个技巧可以用来计算很多不同的日期。下一个例子也是用这个技巧从当前日期来产生不同的日期。


本周的星期一

这里我是用周(wk)的时间间隔来计算哪一天是本周的星期一。

SELECT DATEADD(wk, DATEDIFF(wk,0,getdate()), 0)

一年的第一天

现在用年(yy)的时间间隔来显示这一年的第一天。

SELECT DATEADD(yy, DATEDIFF(yy,0,getdate()), 0)

季度的第一天

假如你要计算这个季度的第一天,这个例子告诉你该如何做。

SELECT DATEADD(qq, DATEDIFF(qq,0,getdate()), 0)

当天的半夜

曾经需要通过getdate()函数为了返回时间值截掉时间部分,就会考虑到当前日期是不是在半夜。假如这样,这个例子使用DATEDIFFDATEADD函数来获得半夜的时间点。

SELECT DATEADD(dd, DATEDIFF(dd,0,getdate()), 0)

深入DATEDIFFDATEADD函数计算

你可以明白,通过使用简单的DATEDIFFDATEADD函数计算,你可以发现很多不同的可能有意义的日期。

目前为止的所有例子只是仅仅计算当前的时间和“1900-01-01”之间的时间间隔数量,然后把它加到“1900-01-01”的时间间隔上来计算出日 期。假定你修改时间间隔的数量,或者使用不同的时间间隔来调用DATEADD函数,或者减去时间间隔而不是增加,那么通过这些小的调整你可以发现和多不同 的日期。

这里有四个例子使用另外一个DATEADD函数来计算最后一天来分别替换DATEADD函数前后两个时间间隔。

上个月的最后一天

这是一个计算上个月最后一天的例子。它通过从一个月的最后一天这个例子上减去3毫秒来获得。有一点要记住,在Sql Server中时间是精确到3毫秒。这就是为什么我需要减去3毫秒来获得我要的日期和时间。

SELECT dateadd(ms,-3,DATEADD(mm, DATEDIFF(mm,0,getdate()), 0))

计算出来的日期的时间部分包含了一个Sql Server可以记录的一天的最后时刻(“23:59:59:997”)的时间。

去年的最后一天

连接上面的例子,为了要得到去年的最后一天,你需要在今年的第一天上减去3毫秒。

SELECT dateadd(ms,-3,DATEADD(yy, DATEDIFF(yy,0,getdate()), 0))

本月的最后一天

现在,为了获得本月的最后一天,我需要稍微修改一下获得上个月的最后一天的语句。修改需要给用DATEDIFF比较当前日期和“1900-01-01” 回的时间间隔上加1。通过加1个月,我计算出下个月的第一天,然后减去3毫秒,这样就计算出了这个月的最后一天。这是计算本月最后一天的SQL脚本。

SELECT dateadd(ms,-3,DATEADD(mm, DATEDIFF(m,0,getdate())+1, 0))

本年的最后一天

你现在应该掌握这个的做法,这是计算本年最后一天脚本

SELECT dateadd(ms,-3,DATEADD(yy, DATEDIFF(yy,0,getdate())+1, 0))


本月的第一个星期一

好了,现在是最后一个例子。这里我要计算这个月的第一个星期一。这是计算的脚本。

select DATEADD(wk, DATEDIFF(wk,0,
dateadd(dd,6-datepart(day,getdate()),getdate())
), 0)

在这个例子里,我使用了本周的星期一的脚本,并作了一点点修改。修改的部分是把原来脚本中“getdate()”部分替换成计算本月的第6天,在计算中用本月的第6天来替换当前日期使得计算可以获得这个月的第一个星期一。

总结

我希望这些例子可以在你用DATEADDDATEDIFF函数计算日期时给你一点启发。通过使用这个计算日期的时间间隔的数学方法,我发现为了显示两个 日期之间间隔的有用历法是有价值的。注意,这只是计算出这些日期的一种方法。要牢记,还有很多方法可以得到相同的计算结果。假如你有其他的方法,那很不 错,要是你没有,我希望这些例子可以给你一些启发,当你要用DATEADDDATEDIFF函数计算你程序可能要用到的日期时。

---------------------------------------------------------------
附录,其他日期处理方法

1)
去掉时分秒
declare @ datetime
set @ = getdate() --'2003-7-1 10:00:00'
SELECT @,DATEADD(day, DATEDIFF(day,0,@), 0)

2
)显示星期几
select datename(weekday,getdate())

3
)如何取得某个月的天数
declare @m int
set @m=2 --
月份
select datediff(day,'2003-'+cast(@m as varchar)+'-15' ,'2003-'+cast(@m+1 as varchar)+'-15')
另外,取得本月天数
select datediff(day,cast(month(GetDate()) as varchar)+'-'+cast(month(GetDate()) as varchar)+'-15' ,cast(month(GetDate()) as varchar)+'-'+cast(month(GetDate())+1 as varchar)+'-15')
或者使用计算本月的最后一天的脚本,然后用DAY函数区最后一天
SELECT Day(dateadd(ms,-3,DATEADD(mm, DATEDIFF(m,0,getdate())+1, 0)))

4
)判断是否闰年:
SELECT case day(dateadd(mm, 2, dateadd(ms,-3,DATEADD(yy, DATEDIFF(yy,0,getdate()), 0)))) when 28 then '
平年' else '闰年' end
或者
select case datediff(day,datename(year,getdate())+'-02-01',dateadd(mm,1,datename(year,getdate())+'-02-01'))
when 28 then '
平年' else '闰年' end

5
)一个季度多少天
declare @m tinyint,@time smalldatetime
select @m=month(getdate())
select @m=case when @m between 1 and 3 then 1
when @m between 4 and 6 then 4
when @m between 7 and 9 then 7
else 10 end
select @time=datename(year,getdate())+'-'+convert(varchar(10),@m)+'-01'
select datediff(day,@time,dateadd(mm,3,@time))

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/1697933/viewspace-888748/,如需转载,请注明出处,否则将追究法律责任。

下一篇: 关于日志
请登录后发表评论 登录
全部评论

注册时间:2008-09-15

  • 博文量
    56
  • 访问量
    510841