如何在SQL Server中截断日期时间?

时间:2009-05-28 21:28:04

标签: sql-server sql-server-2008 datetime truncate

在SQL Server 2008中截断日期时间值(删除小时分钟和秒)的最佳方法是什么?

例如:

declare @SomeDate datetime = '2009-05-28 16:30:22'
select trunc_date(@SomeDate)

-----------------------
2009-05-28 00:00:00.000

13 个答案:

答案 0 :(得分:457)

这仍然经常收集额外的投票,甚至几年后,所以我需要为现代版本的Sql Server更新它。对于Sql Server 2008及更高版本,它很简单:

cast(getDate() As Date)

请注意,底部附近的最后三段仍然适用,您通常需要退后一步,找到一种方法来避免演员阵容。

但也有其他方法可以实现这一目标。这是最常见的。

正确的方法(自Sql Server 2008以来的新功能):

cast(getdate() As Date)

正确的方法(旧):

dateadd(dd, datediff(dd,0, getDate()), 0)

现在已经老了,但它仍然值得知道,因为它也可以轻松适应其他时间点,例如月,分,小时或年的第一时刻。

这种正确的方法使用了作为ansi标准一部分的文档化函数,并且保证可以正常工作,但它可能会慢一些。它的工作原理是查找从第0天到当天的天数,并将这几天添加到第0天。无论您的日期时间如何存储,无论您的语言环境如何,它都能正常工作。

快捷方式:

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

这是有效的,因为datetime列存储为8字节的二进制值。将它们转换为浮动,将它们放置以移除分数,并且当您将它们转换回日期时间时,值的时间部分将消失。它只是位移,没有复杂的逻辑,而且非常快。

请注意,这取决于实施细节Microsoft可以随时更改,即使在自动服务更新中也是如此。它也不是很便携。在实践中,这种实施很可能不会很快改变,但是如果你选择使用它,那么了解危险仍然很重要。现在我们可以选择将其作为约会,但这很少是必要的。

错误的方式:

cast(convert(char(11), getdate(), 113) as datetime)

错误的方法是转换为字符串,截断字符串,然后转换回日期时间。这是错误的,原因有两个:1)它可能无法在所有语言环境中运行; 2)它是最慢的可能方式...而不仅仅是一点点;它比其他选项慢一个数量级或两个数量级。


更新这最近得到了一些投票,所以我想补充说,自从我发布这个以来,我已经看到一些非常可靠的证据表明Sql Server将优化它们之间的性能差异“正确”的方式和“快速”的方式,意味着你现在应该支持前者。

在任何一种情况下,您都希望编写查询以避免首先需要执行此操作。你应该在数据库上做这项工作是非常罕见的。

在大多数地方,数据库已经成为你的瓶颈。通常,服务器是增加硬件以提高性能的最昂贵的服务器,也是最难获得正确添加硬件的服务器(例如,您必须平衡磁盘与内存)。从技术角度和商业角度来看,它也是最难扩展的;在技​​术上添加Web或应用程序服务器比数据库服务器更容易,即使这是假的,您也不需要为IIS或Apache支付每服务器许可证20,000美元。

我想说的是,只要有可能,你应该在应用程序级别完成这项工作。您应该在Sql Server上截断日期时间的时间是您需要按日分组的时间,即使这样,您可能应该将额外的列设置为计算列,并保持在插入/更新时间,或在应用程序逻辑中维护。从数据库中获取这个索引破解,cpu繁重的工作。

答案 1 :(得分:44)

仅限SQL Server 2008

CAST(@SomeDateTime AS Date) 

如果你想要

,那就把它扔回日期时间
CAST(CAST(@SomeDateTime AS Date) As datetime)

答案 2 :(得分:20)

为了更完整的答案,这里有一个截断日期部分的工作方式,包括分钟(将GETDATE()替换为截断日期)。

这与接受的答案不同,您不仅可以使用dd(天),还可以使用任何日期部分(请参阅here):

dateadd(minute, datediff(minute, 0, GETDATE()), 0)

请注意,在上面的表达式中,0是一年开始时的常量日期(1900-01-01)。如果需要截断到较小的部分,例如秒或毫秒,则需要采用一个更接近截断日期的常量日期,以避免溢出。

答案 3 :(得分:7)

我必须这样做时在网上找到的片段是:

 dateadd(dd,0, datediff(dd,0, YOURDATE))
 e.g.
 dateadd(dd,0, datediff(dd,0, getDate()))

答案 4 :(得分:1)

在SQl 2005中,你的trunc_date函数可以这样写。

(1)

CREATE FUNCTION trunc_date(@date DATETIME)
RETURNS DATETIME
AS
BEGIN
    CAST(FLOOR( CAST( @date AS FLOAT ) )AS DATETIME)
END

第一种方法更清洁。它只使用3个方法调用,包括最终的CAST(),并且不执行字符串连接,这是一个自动加号。此外,这里没有巨大的类型演员。如果您可以想象可以表示日期/时间戳,那么从日期转换为数字并返回日期是一个相当简单的过程。

(2)

CREATE FUNCTION trunc_date(@date DATETIME)
RETURNS DATETIME
AS
BEGIN
      SELECT CONVERT(varchar, @date,112)
END

如果您担心微软的日期时间(2)或(3)的实现可能没问题。

(3)

CREATE FUNCTION trunc_date(@date DATETIME)
RETURNS DATETIME
AS
BEGIN
SELECT CAST((STR( YEAR( @date ) ) + '/' +STR( MONTH( @date ) ) + '/' +STR( DAY(@date ) )
) AS DATETIME
END

第三,更详细的方法。这需要将日期分为年,月和日部分,将它们以“yyyy / mm / dd”格式组合在一起,然后将其转换回日期。此方法涉及7个方法调用,包括最终的CAST(),更不用说字符串连接。

答案 5 :(得分:1)

CONVERT(DATE, <yourdatetime>) or CONVERT(DATE, GetDate()) or CONVERT(DATE, CURRENT_TIMESTAMP)

答案 6 :(得分:0)

对于那些来到这里寻找将DATETIME字段截断到不到一整天(例如每分钟)的方法的人,您可以使用:

SELECT CAST(FLOOR(CAST(GETDATE() AS FLOAT)) + (FLOOR((CAST(GETDATE() AS FLOAT) - FLOOR(CAST(GETDATE() AS FLOAT))) * 1440.0) + (3.0/86400000.0)) / 1440.0 AS DATETIME)

所以,如果今天是2010-11-26 14:54:43.123,那么这将返回2010-11-26 14:54:00.000

要更改它所适用的间隔,请将1440.0替换为一天中的间隔数,例如:

24hrs          =   24.0  (for every hour)
24hrs / 0.5hrs =   48.0  (for every half hour)
24hrs / (1/60) = 1440.0  (for every minute)

(总是在末尾添加.0以隐式地转换为浮动。)


对于那些想知道我的计算中(3.0/86400000)是什么的人,SQL Server 2005似乎没有准确地从FLOAT转换为DATETIME,所以这增加了3毫秒地板吧。

答案 7 :(得分:0)

选择cast(floor(cast(getdate()as float))作为datetime) 参考:http://microsoftmiles.blogspot.com/2006/11/remove-time-from-datetime-in-sql-server.html

答案 8 :(得分:0)

此查询应该为您提供相当于Oracle中trunc(sysdate)的结果。

SELECT  * 
FROM    your_table
WHERE   CONVERT(varchar(12), your_column_name, 101)
      = CONVERT(varchar(12), GETDATE(), 101)

希望这有帮助!

答案 9 :(得分:0)

Oracle:

TRUNC(SYSDATE, 'MONTH')

SQL Server:

DATEADD(DAY, - DATEPART(DAY, DateField) + 1, DateField)

可以类似地用于截断日期的分钟或小时。

答案 10 :(得分:0)

你可以这样做(SQL 2008):

  

声明@SomeDate date = getdate()

select @SomeDate

2009-05-28

答案 11 :(得分:0)

在使用分析时,您可能经常需要日期\时间截断。所以我做了一个小函数来帮助解决这个问题:

CREATE FUNCTION TRUNC_DATE
(
    @datetime datetime, -- datetime to be truncated
    @level VARCHAR(10)  -- truncation level: year, month, day, hour and minute
)
RETURNS DATETIME
AS
BEGIN

    IF (UPPER(@level) = 'YEAR')
       RETURN DATEADD(YEAR,   DATEDIFF(YEAR, 0, @datetime), 0)
    ELSE IF (UPPER(@level) = 'MONTH')
        RETURN DATEADD(MONTH,   DATEDIFF(MONTH, 0, @datetime), 0)
    ELSE IF(UPPER(@level) = 'DAY')
       RETURN DATEADD(DAY,   DATEDIFF(DAY, 0, @datetime), 0)
    ELSE IF (UPPER(@level) = 'HOUR')
       RETURN DATEADD(HOUR,   DATEDIFF(HOUR, 0, @datetime), 0)
    ELSE IF (UPPER(@level) = 'MINUTE')
       RETURN DATEADD(MINUTE,   DATEDIFF(MINUTE, 0, @datetime), 0)

    RETURN @datetime
END
GO

要评估函数(使用您的列更改 GETDATE()):

SELECT DBO.TRUNC_DATE(GETDATE(), 'YEAR')   YEAR;
SELECT DBO.TRUNC_DATE(GETDATE(), 'MONTH')  YEAR_MONTH;
SELECT DBO.TRUNC_DATE(GETDATE(), 'DAY')    YEAR_MONTH_DAY;
SELECT DBO.TRUNC_DATE(GETDATE(), 'HOUR')   YEAR_MONTH_DAY_HOUR;
SELECT DBO.TRUNC_DATE(GETDATE(), 'MINUTE') YEAR_MONTH_DAY_HOUR_MINUTE;

输出:

enter image description here

答案 12 :(得分:-1)

TRUNC(aDate,'DD')将截断min,sec和hrs

SRC:http://www.techonthenet.com/oracle/functions/trunc_date.php