在SQL Server中截断日期的最佳方法是什么?

时间:2010-04-14 16:12:14

标签: sql-server tsql

如果我的日期值类似2010-03-01 17:34:12.018

将此转换为2010-03-01 00:00:00.000的最有效方法是什么?

作为第二个问题,模拟Oracle TRUNC函数的最佳方法是什么,这将允许您截断年,季度,月,周,日,小时,分钟和第二边界?

5 个答案:

答案 0 :(得分:31)

要舍入到最近的整天,有三种方法可供广泛使用。第一个使用datediff来查找自0日期时间以来的天数。 0日期时间对应于1900年1月1日。通过将日差添加到开始日期,您已整理到一整天;

select dateadd(d, 0, datediff(d, 0, getdate()))

第二种方法是基于文本的:它使用varchar(10)截断文本描述,只留下日期部分:

select convert(varchar(10),getdate(),111)

第三种方法使用的事实是datetime实际上是一个浮点,表示自1900年以来的天数。因此,通过将其舍入为整数,例如使用floor,您将得到一天的开始:

select cast(floor(cast(getdate() as float)) as datetime)

要回答第二个问题,一周的开始比较棘手。一种方法是减去星期几:

select dateadd(dd, 1 - datepart(dw, getdate()), getdate())

这也返回一个时间部分,因此你必须将它与一个时间剥离方法结合起来才能到达第一个日期。例如,@start_of_day作为可读性的变量:

declare @start_of_day datetime
set @start_of_day = cast(floor(cast(getdate() as float)) as datetime)
select dateadd(dd, 1 - datepart(dw, @start_of_day), @start_of_day)

年,月,小时和分钟的开始仍然适用于“自1900年以来的差异”方法:

select dateadd(yy, datediff(yy, 0, getdate()), 0)
select dateadd(m, datediff(m, 0, getdate()), 0)
select dateadd(hh, datediff(hh, 0, getdate()), 0)
select dateadd(mi, datediff(mi, 0, getdate()), 0)

舍入第二个需要采用不同的方法,因为0以来的秒数会导致溢出。一种方法是使用当天的开头而不是1900作为参考日期:

declare @start_of_day datetime
set @start_of_day = cast(floor(cast(getdate() as float)) as datetime)
select dateadd(s, datediff(s, @start_of_day, getdate()), @start_of_day)

舍入5分钟,请调整分钟舍入方法。取微小差异的商,例如使用/5*5

select dateadd(mi, datediff(mi,0,getdate())/5*5, 0)

这也适用于四分之一小时。

答案 1 :(得分:15)

如果您使用的是SQL Server 2008,则可以使用新的Date数据类型,如下所示:

select cast(getdate() as date)

如果您仍然需要将值设置为DateTime数据类型,则可以执行以下操作:

select cast(cast(getdate() as date) as datetime)

应该适用于所有SQL Server版本的方法是:

select cast(floor(cast(getdate() as float)) as datetime)

答案 2 :(得分:2)

尝试:

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

更新:回答第二个问题: 多年来你可以使用我的答案的一点点修改版本:

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

季度:

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

等等。

我检查了几分钟 - 没关系。但是几秒钟我就收到了溢出信息:

  

两个日期时间列的差异   在运行时导致溢出。

还有一次更新:查看同一question

的以下答案

答案 3 :(得分:2)

这已经很晚了,但会产生帖子中要求的确切结果。我也觉得它比使用dateadd更直观,但这是我的偏好。

declare @SomeDate datetime = '2010-03-01 17:34:12.018'
SELECT 
 DATEFROMPARTS(
     YEAR(@SomeDate)
    ,MONTH(@SomeDate)
    ,'01'
    ) AS CUR_DATE_FROM_PARTS
,DATETIMEFROMPARTS(
     YEAR(@SomeDate)                     
    ,MONTH(@SomeDate)                
    ,'01' --DAY(@SomeDate)                   
    ,'00' --DATEPART(HOUR,@SomeDate)         
    ,'00' --DATEPART(MINUTE,@SomeDate)       
    ,'00' --DATEPART(SECOND,@SomeDate)       
    ,'00' --DATEPART(MILLISECOND,@SomeDate) 
    ) AS CUR_DATETIME_FROM_PARTS
,@SomeDate                         AS CUR_DATETIME
,YEAR(@SomeDate)                   AS CUR_YEAR
,MONTH(@SomeDate)                  AS CUR_MONTH
,DAY(@SomeDate)                    AS CUR_DAY
,DATEPART(HOUR,@SomeDate)          AS CUR_HOUR
,DATEPART(MINUTE,@SomeDate)        AS CUR_MINUTE
,DATEPART(SECOND,@SomeDate)        AS CUR_SECOND
,DATEPART(MILLISECOND,@SomeDate)   AS CUR_MILLISECOND
FROM Your_Table

截断日期:2010-03-01

截断日期时间:2010-03-01 00:00:00.000

DateTime:2010-03-01 17:34:12.017

答案 4 :(得分:0)

不确定这是否是最有效的方法,但我喜欢使用以下简单方法,其中@SomeDate是您的字段。

Concat(Year(@SomeDate), '-', Month(@SomeDate), '-', '01')