在SQL Server中设置日期


71

在SQL Server中,如何将DATETIME“设置”到秒/分钟/小时/天/年?

假设我的日期为2008-09-17 12:56:53.430,那么flooring的输出应为:

  • 年份: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

Answers:


103

关键是使用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,则经常会出现算术溢出。因此,请选择一个已知值,该值一定要小于您要底线的日期时间。


1
您计算偏移量的日期不必是过去的日期。任何日期都可以,只要它本身在问题间隔中处于“底限”即可。如果基准日期是将来的日期,您将得到一个负的偏移值...
MatBailie

如果星期天是一周中的第一天,请使用本周的时间...选择dateadd(week,datediff(week,0,@ datetime),-1)
Davin Studer

如果星期一是一周中的第一天,请使用此选项...选择dateadd(week,datediff(week,0,@ datetime),0)
Davin Studer 2013年

不确定为什么这个答案不是最重要的,这对于Microsoft SQL Server中的日期格式非常有效
亚当(Adam)

29

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

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

您将DateTime转换为一个浮点数,该浮点数将Date表示为整数部分,并将Time表示为经过的一天的一部分。切掉该小数部分,然后将其强制转换回DateTime,这样您就可以在当天开始的午夜。

这可能比所有DATEADD和DATEDIFF东西更有效。这肯定是更容易键入的方式。


1
实际上,这比dateadd(day,datediff(day,0,@ datetime),0)多25%的字符,因此键入起来并不容易。效率也降低了15%。
波特曼

9
@Portman-您的说法是否有效率低15%的依据?
霍根

3
强制转换为地板会损害性能,因为它将跳过任何日期时间索引。使用SQL 2008时,最好使用datediff函数或CAST([field] AS TIME)或CAST([field] as DATE)
Rik 2014年

1
这在SQL Server 2008 R2中不起作用:不允许从数据类型date到float的显式转换。 stackoverflow.com/a/5505975/1919692
droid

@droid-我刚刚在SQL Server 2014中对其进行了测试,并且工作正常。
克里斯·威斯特菲尔德

12

扩展转换/发布解决方案,在Microsoft SQL Server 2008中,您可以执行以下操作:

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

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

此转换不涉及任何字符串。

对于临时查询或更新,这是可以的,但是对于键联接或频繁使用的处理,最好在处理过程中处理转换或将表重新定义为具有适当的键和数据。

在2005年,您可以使用Messenger地板: cast(floor(cast(getdate() as float)) as datetime)

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


6

多年来,我已经多次使用@Portman的答案作为地板日期的参考,并将其工作移至您可能会发现有用的功能中。

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

我要求,如果您决定赞成这个答案,请也赞成@Portman的答案,因为我的代码是他的衍生作品。

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

2

CONVERT()函数可以做到这一点为好,这取决于你用什么样的风格。


2
我们发现CONVERT()的性能可能比dateadd / datediff低10%到5倍。SQL对在数字类型和字符串之间进行转换然后再返回进行转换施加了惩罚。
波特曼

1

不幸的是它不是Oracle,否则您可以使用trunc()或to_char()。

但是我在使用SQL Server时也遇到了类似的问题,并使用了CONVERT()和DateDiff()方法,如此处所述


0

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

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

先前的答案表明了这一点,并对此发表评论(较慢)
Hogan 2014年

0

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

资源


-1

由于PostgreSQL也是“ SQL Server”,因此我将提及

date_trunc()

这恰好可以很好地满足您的要求。

例如:

 选择date_trunc('hour',current_timestamp);
       date_trunc
------------------------
 2009-02-18 07:00:00-08
(1列)


这里的“ SQL Server”是指Microsoft的SQL DBMS。这个名字的确确实令人困惑。
的Aurelien加塞
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.