【问题标题】:Floor a date in SQL server在 SQL Server 中设置日期
【发布时间】:2010-09-10 06:23:30
【问题描述】:

在 SQL Server 中,如何将 DATETIME 设置为秒/分钟/小时/日/年?

假设我的日期是2008-09-17 12:56:53.430,那么地板的输出应该是:

  • 年份:2008-01-01 00:00:00.000
  • 月份:2008-09-01 00:00:00.000
  • 日期:2008-09-17 00:00:00.000
  • 时间:2008-09-17 12:00:00.000
  • 分钟:2008-09-17 12:56:00.000
  • 第二次:2008-09-17 12:56:53.000

【问题讨论】:

    标签: sql-server tsql


    【解决方案1】:

    关键是使用DATEADDDATEDIFF 以及适当的SQL 时间跨度枚举。

    declare @datetime datetime;
    set @datetime = getdate();
    select @datetime;
    select dateadd(year,datediff(year,0,@datetime),0);
    select dateadd(month,datediff(month,0,@datetime),0);
    select dateadd(day,datediff(day,0,@datetime),0);
    select dateadd(hour,datediff(hour,0,@datetime),0);
    select dateadd(minute,datediff(minute,0,@datetime),0);
    select dateadd(second,datediff(second,'2000-01-01',@datetime),'2000-01-01');
    select dateadd(week,datediff(week,0,@datetime),-1); --Beginning of week is Sunday
    select dateadd(week,datediff(week,0,@datetime),0); --Beginning of week is Monday
    

    请注意,当您按秒计算时,如果使用 0,通常会出现算术溢出。因此请选择一个已知值,该值保证低于您尝试计算的日期时间。

    【讨论】:

    • 您计算偏移量的日期不必是过去的日期。任何日期都可以使用,只要它本身“FLOOR”到问题的间隔。如果基准日期在未来,您只会得到一个负偏移值...
    • 如果星期天是一周的第一天,请使用此选项... select dateadd(week,datediff(week,0,@datetime),-1)
    • 如果星期一是一周的第一天,请使用此选项 ... select dateadd(week,datediff(week,0,@datetime),0)
    • 不知道为什么这个答案不在顶部,这对于 Microsoft SQL Server 中的日期格式非常有效
    【解决方案2】:

    在 SQL Server 中,有一个小技巧可以做到这一点:

    SELECT CAST(FLOOR(CAST(CURRENT_TIMESTAMP AS float)) AS DATETIME)
    

    您将 DateTime 转换为浮点数,将 Date 表示为整数部分,将 Time 表示为一天中过去的分数。去掉那个小数部分,然后把它转换回 DateTime,你就得到了那天开始的午夜。

    这可能比所有 DATEADD 和 DATEDIFF 东西更有效。打字当然更容易。

    【讨论】:

    • 实际上,这比 dateadd(day,datediff(day,0,@datetime),0) 多 25% 的字符,所以输入起来并不容易。它的效率也降低了 15%。
    • @Portman - 您声称效率降低 15% 有依据吗?
    • 强制转换为地板会损害性能,因为它会跳过任何日期时间索引。使用 SQL 2008 时,最好使用 datediff 函数或 CAST( [field] AS TIME) 或 CAST( [field] as DATE)
    • 这在 SQL Server 2008 R2 中不起作用:不允许从数据类型 date 到 float 的显式转换。 stackoverflow.com/a/5505975/1919692
    • @droid - 我刚刚在 SQL Server 2014 中对其进行了测试,它运行良好。
    【解决方案3】:

    扩展 Convert/Cast 解决方案,在 Microsoft SQL Server 2008 中,您可以执行以下操作:

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

    只需将getdate() 替换为任何日期时间列即可。

    此转换不涉及字符串。

    这对于即席查询或更新是可以的,但对于键连接或大量使用的处理,最好在处理中处理转换或重新定义表以具有适当的键和数据。

    2005年可以使用梅西尔地板:cast(floor(cast(getdate() as float)) as datetime)

    我不认为这也使用字符串转换,但我无法将实际效率与扶手椅估计进行比较。

    【讨论】:

      【解决方案4】:

      多年来,我多次使用@Portman's answer 作为地板日期的参考,并将其工作转移到您可能会发现有用的功能中。

      我对它的性能不做任何声明,只是将它作为一种工具提供给用户。

      我问的是,如果您决定支持这个答案,也请支持 @Portman's answer,因为我的代码是他的派生代码。

      IF OBJECT_ID('fn_FloorDate') IS NOT NULL DROP FUNCTION fn_FloorDate
      SET ANSI_NULLS OFF
      GO
      SET QUOTED_IDENTIFIER ON
      GO
      CREATE FUNCTION [dbo].[fn_FloorDate] (
        @Date DATETIME = NULL,
        @DatePart VARCHAR(6) = 'day'
      )
      RETURNS DATETIME
      AS
      BEGIN
        IF (@Date IS NULL)
          SET @Date = GETDATE();
      
        RETURN
        CASE
          WHEN LOWER(@DatePart) = 'year' THEN DATEADD(YEAR, DATEDIFF(YEAR, 0, @Date), 0)
          WHEN LOWER(@DatePart) = 'month' THEN DATEADD(MONTH, DATEDIFF(MONTH, 0, @Date), 0)
          WHEN LOWER(@DatePart) = 'day' THEN DATEADD(DAY, DATEDIFF(DAY, 0, @Date), 0)
          WHEN LOWER(@DatePart) = 'hour' THEN DATEADD(HOUR, DATEDIFF(HOUR, 0, @Date), 0)
          WHEN LOWER(@DatePart) = 'minute' THEN DATEADD(MINUTE, DATEDIFF(MINUTE, 0, @Date), 0)
          WHEN LOWER(@DatePart) = 'second' THEN DATEADD(SECOND, DATEDIFF(SECOND, '2000-01-01', @Date), '2000-01-01')
          ELSE DATEADD(DAY, DATEDIFF(DAY, 0, @Date), 0)
        END;
      END
      

      用法:

      DECLARE @date DATETIME;
      SET @date = '2008-09-17 12:56:53.430';
      
      SELECT
        @date AS [Now],--2008-09-17 12:56:53.430
        dbo.fn_FloorDate(@date, 'year') AS [Year],--2008-01-01 00:00:00.000
        dbo.fn_FloorDate(default, default) AS [NoParams],--2013-11-05 00:00:00.000
        dbo.fn_FloorDate(@date, default) AS [ShouldBeDay],--2008-09-17 00:00:00.000
        dbo.fn_FloorDate(@date, 'month') AS [Month],--2008-09-01 00:00:00.000
        dbo.fn_FloorDate(@date, 'day') AS [Day],--2008-09-17 00:00:00.000
        dbo.fn_FloorDate(@date, 'hour') AS [Hour],--2008-09-17 12:00:00.000
        dbo.fn_FloorDate(@date, 'minute') AS [Minute],--2008-09-17 12:56:00.000
        dbo.fn_FloorDate(@date, 'second') AS [Second];--2008-09-17 12:56:53.000
      

      【讨论】:

      • 我建议您在 'year'... 时使用 case lower(@DatePart),而不是 case when lower(... 以避免所有不必要的代码和较低的转换。
      【解决方案5】:

      CONVERT() 函数也可以执行此操作,具体取决于您使用的样式。

      【讨论】:

      • 我们发现 CONVERT() 的性能比 dateadd/datediff 低 10% 到 5 倍。 SQL 对数字类型和字符串之间的转换施加惩罚,然后再返回。
      【解决方案6】:

      可惜它不是 Oracle,否则你可以使用 trunc() 或 to_char()。

      但我在使用 SQL Server 时遇到了类似的问题,并使用了 CONVERT() 和 DateDiff() 方法,如引用 here

      【讨论】:

        【解决方案7】:

        有几种方法可以给这只猫剥皮 =)

        select convert(datetime,convert(varchar,CURRENT_TIMESTAMP,101))
        

        【讨论】:

        • 先前的回答提出了这一点并被评论为(较慢)
        【解决方案8】:

        DateAdd 和 DateDiff 可以帮助完成许多不同的任务。例如,您可以找到任何一个月的最后一天,也可以找到上个月或下个月的最后一天。

        ----Last Day of Previous Month
        SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE()),0))
        LastDay_PreviousMonth
        ----Last Day of Current Month
        SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+1,0))
        LastDay_CurrentMonth
        ----Last Day of Next Month
        SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+2,0))
        LastDay_NextMonth
        

        Source

        【讨论】:

          【解决方案9】:

          既然PostgreSQL也是一个“SQL Server”,我就提一下

          date_trunc()
          

          这正是你优雅地问的问题。

          例如:

          选择 date_trunc('hour',current_timestamp); 日期截断 ---------------------- 2009-02-18 07:00:00-08 (1 行)

          【讨论】:

          • "SQL Server" 这里指的是微软的 SQL DBMS。这个名字确实很混乱。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多