如何从SQL Server DateTime数据类型中仅返回日期?

2170
SELECT GETDATE()

返回:2008-09-22 15:24:13.790

我想要仅包含日期部分而没有时间部分:2008-09-22 00:00:00.000

如何获得这个结果?


21
需要注意的一点是,SQL Server 2008包括一个单独的DATE数据类型,用于存储仅包含日期而不含时间部分的数据。更多信息请参见:http://www.sql-server-performance.com/articles/dev/datetime_2008_p1.aspx - Ben Hoffstein
7
不要错过这篇文章,其中展示了各种去除日期时间值中时间部分的方法性能测试结果。 - ErikE
3
@Martin 奇怪,谢谢,让我们再试一次 - Aaron Bertrand
21
不要被票数和被接受的答案所误导,看一下https://dev59.com/1HVD5IYBdhLWcg3wBm1h#126984 - Rohit Vipin Mathews
8
你错误地假设人们只关心2008版本。(实际上还有其他版本。) 投票结果说明了一切。 - hktegner
显示剩余4条评论
46个回答

2838

注意:此答案返回原始的DATETIMEDATETIME2类型。要使用返回真正的DATE类型的表达式(适用于SQL Server 2008及更高版本),请参见下面BenR的答案。

SELECT DATEADD(dd, 0, DATEDIFF(dd, 0, @your_date))

例如

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

给我

2008-09-22 00:00:00.000

优点:

  • 无需进行varchar<->datetime的转换
  • 无需考虑地区设置

63
看起来这个方法比通常使用的双重convert()方法快35%(我也用了好多年)。很不错。+1 - Dane
8
我能看到你解决方案的唯一缺点是,除非你知道它在做什么,否则它有点晦涩难懂。使用双重转换方法可以使你的意图更明显,便于未来代码维护人员理解。顺便说一下,我没有给你投反对票。我想我也会开始使用你的方法。谢谢@aku。 - Jim Birchall
41
将日期时间设为当天的午夜确实不包含时间。您期望得到什么结果?datetime数据类型不能完全没有时间。我认为您正在混淆数据存储和用户呈现。如果您只想显示给用户一个没有时间部分(不是零,只是空白)的字符串,则只需使用Convert(varchar(30), @Date, 101)或类似的东西即可。有关更多信息,请参阅SQL Server Books Online • Cast and Convert - ErikE
8
datetime 数据类型始终包含日期和时间,不能合理地将它们分开存储——除非您使用 SQL Server 2008,在这种情况下还有单独的“date”和“time”数据类型。如果您使用 CONVERT(),那么您真正想要的是一个字符串以备日后使用,因此您将被困在这种方式中,尽管最好使用日期格式化函数而不是截取日期——或通过 CAST(... AS DATE)CONVERT(DATE, ...) 来实现,这在本页面上已经提到了很多次。 - Magnus
12
我建议将答案更改为SELECT DATEADD(dd, DATEDIFF(dd, 0, @your_date), 0),因为这样就可以将“dd”替换为任何其他datepart关键字,以在任意级别上截断你的datetime - Michael
显示剩余9条评论

927

SQLServer 2008现在具有一个“日期”数据类型,仅包含日期而没有时间组件。任何使用SQLServer 2008及以上版本的人都可以执行以下操作:

SELECT CONVERT(date, GETDATE())

47
在SQL2008中还有“时间”数据类型,它回答了将日期和时间分离的问题的另一半。 - misteraidan
10
我对日期时间戳的不同削减方法进行了基准测试,这是最快的方法。虽然差距很小,但在大量执行中它显然更快。 - UnhandledExcepSean
2
SQL Server 2005怎么样? - Dr. MAF
@Dr.MAF 完成循环,2008年之前的答案在这里:https://dev59.com/1HVD5IYBdhLWcg3wBm1h - Frosty840
在 SQL 2019 中,哪个更受青睐 - 这个答案还是 CAST 或 CONVERT? - variable

235

如果使用 SQL 2008 或更新版本:

select cast(getdate() as date)

3
你使用哪个版本的SQL Server?需要什么类型和日期? - abatishchev
8
注意!声明@date1为datetime类型,值为'2015-09-30 20:59:59.999'; 使用select cast(@date1 as date)操作将返回'2015-10-01'。 - Nick
8
@Nick: 这个问题与 DateTime 有关,使用 DateTime2 替代即可解决,http://sqlfiddle.com/#!6/9eecb7/2833 。 - abatishchev
10
为了补充abatishchev的回答,你提供的@date1实际上是“2015-10-01”,这是由于DateTime的限制。如果不进行任何类型转换,则结果也为“2015-10-01”!例如:declare @date1 datetime = '2015-09-30 23:59:59.999';select @date1 => 2015-10-01 - Frédéric
5
这是一个易于记忆的SQL技巧之一。正如Mike所说,只适用于2008及以后的版本,但如果你在某处找到了2005年及之前的数据库,可能会遇到很多问题 :) - NicVerAZ
显示剩余8条评论

87

DATEADD和DATEDIFF比转换为varchar更好。两个查询具有相同的执行计划,但是执行计划主要涉及数据访问策略,并不总是揭示执行所有操作所需的CPU时间中涉及的隐式成本。如果这两个查询运行在一个拥有数百万行的表上,则使用DateDiff的CPU时间可能接近于Convert CPU时间的1/3!

要查看查询的执行计划:

set showplan_text on
GO 

DATEDIFF和DATEADD都会执行CONVERT_IMPLICIT。

虽然对于某些人来说,使用CONVERT的解决方案更简单、更易于阅读,但它更慢。没有必要将其转换回DateTime(这是服务器隐式完成的)。在DateDiff方法中也没有真正需要在之后使用DateAdd,因为整数结果也将隐式转换回DateTime。


SELECT CONVERT(varchar, MyDate, 101) FROM DatesTable

  |--Compute Scalar(DEFINE:([Expr1004]=CONVERT(varchar(30),[TEST].[dbo].[DatesTable].[MyDate],101)))
       |--Table Scan(OBJECT:([TEST].[dbo].[DatesTable]))

从 DatesTable 表中选取 MyDate 字段,将其转为日期类型,并去掉时间部分。


  |--Compute Scalar(DEFINE:([Expr1004]=dateadd(day,(0),CONVERT_IMPLICIT(datetime,datediff(day,'1900-01-01 00:00:00.000',CONVERT_IMPLICIT(datetime,[TEST].[dbo].[DatesTable].[MyDate],0)),0))))
       |--Table Scan(OBJECT:([TEST].[dbo].[DatesTable]))

像@digi建议的那样使用FLOOR()函数的性能接近于DateDiff,但不推荐,因为将DateTime数据类型转换为float类型再转换回来并不总是会得到原始值。

记住:不要相信任何人。查看性能统计数据并自己测试!

在测试结果时要小心。将许多行选择到客户端会隐藏性能差异,因为发送行集到网络比执行计算需要更长的时间。所以请确保所有行的工作都由服务器完成,但没有行集发送到客户端。

对于一些人来说,缓存优化何时影响查询似乎有些困惑。在同一批次或不同批次中运行两个查询对缓存没有影响。因此,您可以手动使缓存过期,也可以简单地反复运行查询多次。对查询#2的任何优化也将影响任何后续查询,因此如果愿意,可以放弃执行#1。

这里是完整的测试脚本和性能结果,证明DateDiff比转换为varchar要快得多。


Ricardo C,好的调查!您使用哪个版本的SQL服务器?在MSSQL2000方法中,datediff的执行速度对我来说略快。 - aku
只是提一下,我进行了1000.000次测试。对于实际场景,性能差异不会很明显,我想。 - aku
Aku,我在这个测试中使用了 SQL Server 2005 Express。在工作中,我使用的是 2000 版本,我将使用一个超过 2400 万行的表进行测试,并观察结果。 - Ricardo C
Aku,相同的结果。在一千万行数据上没有性能差异。 - Ricardo C
7
有关性能相等的说法并不正确。当然,执行计划将是相同的!!! 必须通过比较 CPU 使用情况来衡量这些性能,而非检查执行计划。 - ErikE

61

试试这个:

SELECT CONVERT(VARCHAR(10),GETDATE(),111)

上面的语句将您当前的格式转换为YYYY/MM/DD,请参考此链接选择您喜欢的格式。


5
这对我来说返回的是“2008/09/22”。 - Eddie Groves
3
SELECT CONVERT(VARCHAR(10),GETDATE(),101) 是 mm/dd/yyyy 格式。 - Flea
5
如果您基于原始文本值(在数据库外部)进行排序,则“日语”格式更好。 - Simon_Weaver

50
SELECT CONVERT(datetime, CONVERT(varchar, GETDATE(), 101))

32

只需执行以下操作:

SELECT CAST(date_variable AS date)

或者在 PostgreSQL 中使用:

SELECT date_variable::date

这被称为类型转换!


30

返回日期格式的方法:

CAST(OrderDate AS date)

上述代码适用于SQL Server 2010。

它将返回类似于12/12/2013的日期格式。

对于SQL Server 2012,请使用以下代码:

CONVERT(VARCHAR(10), OrderDate , 111)

1
这会返回一个零时间的日期,而不仅仅是日期。 - Bohemian
1
你能告诉我你正在使用哪个版本的SQL Server吗? - Mahesh ML
1
@MaheshML 在 MS SQL 2012 中,它返回日期和时间。 - Marek
1
在 SQL Azure 中像魔法一样运行。 - Martín Coll
5
SQL Server 2010这个东西不存在。 - SvenAelterman
1
我认为“SQL Server 2010”指的是SQL Server 2008 R2(它在2010年发布)。 - J. Chris Compton

25

24

如果你需要结果作为 varchar 类型,你应该通过以下步骤进行

SELECT CONVERT(DATE, GETDATE()) --2014-03-26
SELECT CONVERT(VARCHAR(10), GETDATE(), 111) --2014/03/26
上面已经提到过。
  • 如果你需要以日期和时间格式呈现结果,应该使用以下任意一种查询:
  • SELECT CONVERT(DATETIME, CONVERT(VARCHAR(10), GETDATE(), 111)) AS OnlyDate 
    

    2014年3月26日 00:00:00.000

  • SELECT CONVERT(DATETIME, CONVERT(VARCHAR(10), GETDATE(), 112)) AS OnlyDate 
    

    2014年3月26日 00:00:00.000

  • DECLARE  @OnlyDate DATETIME
    SET @OnlyDate = DATEDIFF(DD, 0, GETDATE())
    SELECT @OnlyDate AS OnlyDate
    

    2014年3月26日 00:00:00.000


  • 网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,