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


1777
SELECT GETDATE()

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

我希望该日期部分没有时间部分: 2008-09-22 00:00:00.000

我该怎么办?


4
如果您希望获取不带时间的日期数据类型,即使时间为00:00:00,那么您也很不走运,您可以获取varchar,但结构为datetime,因此您将始终有一些时间。
昆汀·罗宾逊

16
需要注意的一件事是,SQL Server 2008包含一个单独的DATE数据类型,用于仅存储日期而没有时间成分。此处的更多信息: sql-server-performance.com/articles/dev/datetime_2008_p1.aspx
Ben

7
不要错过显示各种时间删除方法的性能测试结果的帖子
ErikE 2012年

18
不要被投票和接受的答案误导,请看一下stackoverflow.com/a/126984/1155650
Rohit Vipin Mathews 2013年

8
@Rohit您错误地认为2008是人们唯一关心的版本。(在野外还有更多版本。)选票本身就是发言。
hktegner 2013年

Answers:


2486

以后SQL Server 2008,您应该CONVERT

SELECT CONVERT(date, getdate())

在旧版本上,您可以执行以下操作:

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转换
  • 不用考虑 locale

正如迈克尔建议的

使用此变体: SELECT DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)

select getdate()

SELECT DATEADD(hh, DATEDIFF(hh, 0, getdate()), 0)
SELECT DATEADD(hh, 0, DATEDIFF(hh, 0, getdate()))

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

SELECT DATEADD(mm, DATEDIFF(mm, 0, getdate()), 0)
SELECT DATEADD(mm, 0, DATEDIFF(mm, 0, getdate()))

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

输出:

2019-04-19 08:09:35.557

2019-04-19 08:00:00.000
4763-02-17 00:00:00.000

2019-04-19 00:00:00.000
2019-04-19 00:00:00.000

2019-04-01 00:00:00.000
1903-12-03 00:00:00.000

2019-01-01 00:00:00.000
1900-04-30 00:00:00.000

52
+1看起来这比常用的double convert()方法快35%(我也已经使用了多年)。好一个。
戴恩

8
我可以看到您的解决方案的唯一缺点是,除非您知道它在做什么,否则它有点钝。使用double convert方法可使您的意图对于futire代码维护者更加明显。顺便说一句,我还没有投票赞成你。我想我也会开始使用您的方法。Thankyou @aku
Jim Birchall

38
@pilavdzice将日期时间设置为该日的午夜,则不会离开该时间。您期待什么结果?该datetime数据类型不能有根本没有时间。我认为您将数据存储与用户演示混淆了。如果您想要的只是一种向用户显示没有时间部分的字符串(不是零,只是空白)的方式,那么您只是想要Convert(varchar(30), @Date, 101)或类似的东西。有关更多信息,请参见SQL Server联机丛书•转换和转换
ErikE 2012年

7
@ user1671639 datetime数据类型始终包含日期和时间,您不能明智地存储日期和时间,除非您使用的是SQL Server 2008,除非您使用的是SQL Server 2008,否则还会有单独的“日期”和“时间”数据类型。如果您这样使用CONVERT(),则确实需要一个字符串供以后使用,因此您将被困在那样的情况下-尽管使用日期格式函数而不是缩短日期会更好-或通过CAST(... AS DATE)CONVERT(DATE, ...),在此页面上经常提到。
Magnus

10
我建议将答案更改为,SELECT DATEADD(dd, DATEDIFF(dd, 0, @your_date), 0)因为这样dd可以将其替换为任何其他datepart关键字以datetime在任意级别截断您的关键字。
Michael-Clay Shirky在哪里,2014年

717

SQLServer 2008现在具有“日期”数据类型,该数据类型仅包含没有时间成分的日期。使用SQLServer 2008及更高版本的任何人都可以执行以下操作:

SELECT CONVERT(date, GETDATE())

41
SQL2008中还有一个“时间”数据类型,可以回答日期和时间分隔问题的另一半。
misteraidan 2011年

8
仅供参考,我以基准日期缩短日期的不同方法作为基准,这是最快的方法。当然,差异很小,但是在大量执行过程中显然更快。
UnhandledExcepSean 2014年

2
wt关于sqlserver 2005?
MAF博士

@ Dr.MAF圆满完成,2008年前的答案在这里:stackoverflow.com/questions/113045/…–
Frosty840

170

如果使用SQL 2008及更高版本:

select cast(getdate() as date)

3
@FredrickGauss:什么类型,日期?您使用什么版本的SQL Server?
abatishchev 2012年

7
谨防!声明@ date1 datetime ='2015-09-30 20:59:59.999'; select cast(@ date1作为日期)返回'2015-10-01'–
Nick

6
@Nick:这是DateTime的问题。使用DateTime2代替,它工作正常。sqlfiddle.com/#!6/9eecb7/2833
abatishchev 2015年

8
@Nick,作为补充abatishchev的响应2015-10-01,由于DateTime限制,您的@ date1实际上是。尝试不强制转换为Date,它2015-10-01也会产生收益!declare @date1 datetime = '2015-09-30 23:59:59.999';select @date1=>2015-10-01
弗雷德里克

4
这些容易记住的SQL技巧之一。正如Mike所说,只有2008年以后,但是,如果您在某个地方找到了2005年和以前的DB,则可能会有很多问题:)
NicVerAZ 2015年

73

DATEADD和DATEDIFF优于转换为varchar。两个查询都具有相同的执行计划,但是执行计划主要是关于数据访问策略的,并不总是显示执行所有步骤所花费的CPU时间所隐含的成本。如果两个查询都针对具有数百万行的表运行,则使用DateDiff的CPU时间可能接近“转换CPU时间”的1/3!

要查看查询的执行计划:

set showplan_text on
GO 

DATEADD和DATEDIFF都将执行CONVERT_IMPLICIT。

虽然CONVERT解决方案更简单,更容易阅读一些,它速度较慢。无需回退到日期时间(这是由服务器隐式完成的)。之后,DateAdd的DateDiff方法中也没有真正的需求,因为整数结果也将隐式转换回datetime。


从DatesTable中选择转换(varchar,MyDate,101)

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

从DatesTable中选择SELECT DATEADD(dd,0,DATEDIFF(dd,0,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]))

使用FLOOR()作为@digi建议的性能接近于DateDiff,但不建议这样做,因为将datetime数据类型强制转换为float和back并不总是产生原始值。

记住伙计们:不要相信任何人。查看性能统计信息,然后自己进行测试!

测试结果时请多加注意。选择许多行给客户端将隐藏性能差异,因为通过网络发送行比执行计算花费的时间更长。因此,请确保所有行的工作均由服务器完成,但没有行集发送给客户端。

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

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


里卡多C,很好的调查!您使用什么版本的SQL Server?在带有datediff的MSSQL2000方法上,对我来说执行速度稍快。
aku

请注意,我执行了1000.000次测试。对于真实场景,性能差异不会很明显,我猜
aku

Aku,我为此测试使用了SQL Server 2005 Express。我使用2000进行工作,我将使用一个超过2400万行的表对其进行测试,然后看看会产生什么结果。
里卡多(Ricardo C)

Aku,相同的结果。超过一千万行的性能没有差异。
里卡多(Ricardo C)

5
关于性能平等的主张是不正确的。当然执行计划是一样的!!!必须通过比较CPU使用率而不是检查执行计划来衡量这些服务器的性能。
埃里克

51

尝试这个:

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

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


5
这将为我返回“ 2008/09/22”
eddiegroves 08/09/22

1
SELECT CONVERT(VARCHAR(10),GETDATE(),101)是mm/dd/yyyy格式。
跳蚤

4
如果您基于原始文本值(数据库外部)进行排序,则“日语”格式更好
-Simon_Weaver


21

以日期格式返回

CAST(OrderDate AS日期)

上面的代码将在sql server 2010中工作

它将在2013年12月12日返回

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

CONVERT(VARCHAR(10), OrderDate , 111)

1
这使我返回零时间的日期,而不仅仅是日期
波西米亚语

1
我能知道您使用的是哪个版本的SQL Server?
Mahesh ML 2014年

1
@MaheshML返回日期和时间在MS SQL 2012年
马立克

1
就像在SQL Azure中的魅力
马丁科尔

5
@MaheshML没有SQL Server 2010这样的东西
。– SvenAelterman


16

如果您需要将结果作为varchar,则应通过

SELECT CONVERT(DATE, GETDATE()) --2014-03-26
SELECT CONVERT(VARCHAR(10), GETDATE(), 111) --2014/03/26

上面已经提到了

如果您需要日期和时间格式的结果,则应使用以下任何查询

  1. SELECT CONVERT(DATETIME, CONVERT(VARCHAR(10), GETDATE(), 111)) AS OnlyDate 

    2014-03-26 00:00:00.000

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

    2014-03-26 00:00:00.000

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

    2014-03-26 00:00:00.000


14
SELECT CONVERT(VARCHAR,DATEADD(DAY,-1,GETDATE()),103) --21/09/2011

SELECT CONVERT(VARCHAR,DATEADD(DAY,-1,GETDATE()),101) --09/21/2011

SELECT CONVERT(VARCHAR,DATEADD(DAY,-1,GETDATE()),111) --2011/09/21

SELECT CONVERT(VARCHAR,DATEADD(DAY,-1,GETDATE()),107) --Sep 21, 2011

13

使用FLOOR()-仅削减时间部分。

SELECT CAST(FLOOR(CAST(GETDATE() AS FLOAT)) AS DATETIME)

4
此方法不是最快的方法,并且还隐含地告诉人们,将日期强制转换为浮点数是准确的,但事实并非如此。请参阅此帖子以获取更多详细信息。
ErikE

13

如果您使用的是SQL Server 2012或更高版本

采用 Format()功能。

SQL Server已经有多种答案和格式类型。但是大多数方法在某种程度上是模棱两可的,您将很难记住与特定日期格式有关的格式类型或函数的数字。这就是为什么在下一版本的SQL Server中会有更好的选择。

FORMAT ( value, format [, culture ] )

文化选项非常有用,因为您可以根据观众指定日期。

您必须记住d(用于小图案)和D(用于长图案)。

1.“ d”-短日期模式。

2009-06-15T13:45:30 -> 6/15/2009 (en-US)
2009-06-15T13:45:30 -> 15/06/2009 (fr-FR)
2009-06-15T13:45:30 -> 2009/06/15 (ja-JP)

2.“ D”-长日期模式。

2009-06-15T13:45:30 -> Monday, June 15, 2009 (en-US)
2009-06-15T13:45:30 -> 15 июня 2009 г. (ru-RU)
2009-06-15T13:45:30 -> Montag, 15. Juni 2009 (de-DE)

查询中的更多示例。

DECLARE @d DATETIME = '10/01/2011';
SELECT FORMAT ( @d, 'd', 'en-US' ) AS 'US English Result'
      ,FORMAT ( @d, 'd', 'en-gb' ) AS 'Great Britain English Result'
      ,FORMAT ( @d, 'd', 'de-de' ) AS 'German Result'
      ,FORMAT ( @d, 'd', 'zh-cn' ) AS 'Simplified Chinese (PRC) Result'; 

SELECT FORMAT ( @d, 'D', 'en-US' ) AS 'US English Result'
      ,FORMAT ( @d, 'D', 'en-gb' ) AS 'Great Britain English Result'
      ,FORMAT ( @d, 'D', 'de-de' ) AS 'German Result'
      ,FORMAT ( @d, 'D', 'zh-cn' ) AS 'Chinese (Simplified PRC) Result';

US English Result Great Britain English Result  German Result Simplified Chinese (PRC) Result
----------------  ----------------------------- ------------- -------------------------------------
10/1/2011         01/10/2011                    01.10.2011    2011/10/1

US English Result            Great Britain English Result  German Result                    Chinese (Simplified PRC) Result
---------------------------- ----------------------------- -----------------------------  ---------------------------------------
Saturday, October 01, 2011   01 October 2011               Samstag, 1. Oktober 2011        2011101

如果需要更多格式,可以转到:

  1. 标准日期和时间格式字符串
  2. 自定义日期和时间格式字符串

12

如果您要使用CONVERT并获得与原始问题相同的输出,即yyyy-mm-dd,则使用CONVERT(varchar(10),[SourceDate as dateTime],121)与前几个答案相同的代码,但是要用破折号将其转换为yyyy-mm-dd的代码是121。

如果我可以使用肥皂盒一秒钟,则这种格式不属于数据层,这就是为什么直到SQL Server 2008才出现实际的datepart数据类型时才没有愚蠢的高开销“技巧”是不可能的介绍。在数据层中进行此类转换会极大地浪费DBMS的开销,但是更重要的是,第二次执行类似的操作之后,您基本上已经创建了内存中孤立的数据,我认为您将随后返回程序。您不能将其放回另一个3NF +列中,也不能将其与任何类型的内容进行比较而不进行还原,因此,您所做的只是引入了故障点并删除了关系引用。

您应该始终将您的dateTime数据类型返回给调用程序,并在PRESENTATION层中进行必要的调整。在将事物返回给调用者之前先进行转换,就从应用程序中消除了所有引用完整性的希望。除非您进行某种手动还原,否则这将再次阻止UPDATE或DELETE操作,这又在不需要时将数据暴露于人为/代码/ gremlin错误。


1
除非,例如,如果您要查询的是检索与用户提供的日期匹配的所有记录作为某个时间字段的日期部分的查询。祝您好运,只有在表示层才能做到这一点。(您不需要转换,可以使用日期算术,但是您会明白…)
Andrew Lazarus

1
@Andrew为什么这么重要?您说WHERE col >= @Date AND col < DATEADD(DAY, 1, @Date);-绝对没有理由在专栏里浪费时间。
亚伦·

1
@AaronBertrand仅在输入@Date的时间部分为零的情况下起作用。如果情况并非如此,您仍然需要知道如何在服务器端截断时间。我同意这个答案,即格式化应留给表示层,但我不同意暗示将其留在前端意味着您不必知道快速的截断方法。
Andrew Lazarus

1
@Andrew您所要做的就是将输入参数设置为DATE。我的观点仍然是,即使那是大多数人的本能,您也不必将任何此类截断应用于
亚伦·伯特兰

1
@AaronBertrand和那个假定您已经在参数的数据类型控制。在存储过程中很好,在其他情况下则不太可能。为什么不进行强制转换以确保参数是您想要和需要的类型?
安德鲁·拉扎鲁斯

10
SELECT DATEADD(DD, DATEDIFF(DD, 0, GETDATE()), 0)

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

SELECT CONVERT(DATETIME, CONVERT(VARCHAR(10), GETDATE(), 101))

编辑:前两个方法基本相同,并执行转换为varchar方法。


1
这些方法都很不错,但是您建议使用哪个方法呢?
eddiegroves

3
需要注意的是前两名的“正确”的版本select dateadd(dd, datediff(dd, 0, getdate()), 0),因为ddS可随后被换出任何的datepart关键字,夹在你选择的任何部分的日期。(还请注意,这dd只是。的缩写day。)
Michael-Clay Shirky在哪里,2014年



7

如果要将结果分配给列或变量,请为其指定DATE类型,并且转换是隐式的。

DECLARE @Date DATE = GETDATE()   

SELECT @Date   --> 2017-05-03

6

我认为这将适合您的情况:

CONVERT(VARCHAR(10),Person.DateOfBirth,111) AS BirthDate
//here date is obtained as 1990/09/25

6
DECLARE @yourdate DATETIME = '11/1/2014 12:25pm'    
SELECT CONVERT(DATE, @yourdate)

2
此建议已被其他答案覆盖(不止一次)。
Andriy M 2014年

6

好的,虽然我来晚了:),这是另一个解决方案。

SELECT CAST(FLOOR(CAST(GETDATE() AS FLOAT)) as DATETIME)

结果

2008-09-22 00:00:00.000

如果您使用的是SQL Server 2012及更高版本,则可以使用如下FORMAT()功能-

SELECT FORMAT(GETDATE(), 'yyyy-MM-dd')

您的第一个示例仍然具有时间成分。问题的关键是如何删除它。
Zack

5

即使使用古老的MSSQL Server 7.0,此处的代码(由该链接提供)也使我可以获得当时需要的日期格式:

PRINT '1) Date/time in format MON DD YYYY HH:MI AM (OR PM): ' + CONVERT(CHAR(19),GETDATE())  
PRINT '2) Date/time in format MM-DD-YY: ' + CONVERT(CHAR(8),GETDATE(),10)  
PRINT '3) Date/time in format MM-DD-YYYY: ' + CONVERT(CHAR(10),GETDATE(),110) 
PRINT '4) Date/time in format DD MON YYYY: ' + CONVERT(CHAR(11),GETDATE(),106)
PRINT '5) Date/time in format DD MON YY: ' + CONVERT(CHAR(9),GETDATE(),6) 
PRINT '6) Date/time in format DD MON YYYY HH:MM:SS:MMM(24H): ' + CONVERT(CHAR(24),GETDATE(),113)

它产生了以下输出:

1) Date/time in format MON DD YYYY HH:MI AM (OR PM): Feb 27 2015  1:14PM
2) Date/time in format MM-DD-YY: 02-27-15
3) Date/time in format MM-DD-YYYY: 02-27-2015
4) Date/time in format DD MON YYYY: 27 Feb 2015
5) Date/time in format DD MON YY: 27 Feb 15
6) Date/time in format DD MON YYYY HH:MM:SS:MMM(24H): 27 Feb 2015 13:14:46:630

5

日期:

SELECT CONVERT(日期,GETDATE())
SELECT CAST(GETDATE()作为日期)

时间:

SELECT CONVERT(时间,GETDATE(),114)
SELECT CAST(GETDATE()作为时间)

5

只需执行以下操作即可:

SELECT CONVERT(date, getdate())
SELECT DATEADD(dd, 0, DATEDIFF(dd, 0, @your_date))
SELECT DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE()))

输出为:

2008-09-22 00:00:00.000

或者干脆像这样:

SELECT CONVERT (DATE, GETDATE()) 'Date Part Only'

结果:

Date Part Only
--------------
2013-07-14

4

为什么不使用DATE_FORMAT(your_datetiem_column,'%d-%m-%Y')?

例如: select DATE_FORMAT( some_datetime_column, '%d-%m-%Y' ) from table_name

您可以通过重新安排'%d-%m-%Y'部分来更改m,d和year的顺序


4

我知道这很老,但是我看不到有人这样说。据我所知,这是ANSI标准。

SELECT CAST(CURRENT_TIMESTAMP AS DATE)

如果Microsoft还可以支持ANSI标准CURRENT_DATE变量,那将是很好的。


select {fn current_date()} as today为我工作。
brianary

@brianary-很好,但是不是ANSI SQL。
点燃

这很公平,而且您的答案很好移植,但是我认为只要我们围绕T-SQL进行工作,它也可以工作(并表明对于MS而言,实现ANSI CURRENT_DATE并不重要)。
brianary

4

我赞成以下未提及的内容:

DATEFROMPARTS(DATEPART(yyyy, @mydatetime), DATEPART(mm, @mydatetime), DATEPART(dd, @mydatetime))

它也不在乎本地或进行双转换-尽管每个'datepart'可能都在做数学运算。因此,它可能比datediff方法要慢一些,但是对我来说,它要清晰得多。特别是当我只想按年和月分组(将日期设置为1)时。


4

从SQL SERVER 2012开始,您可以执行以下操作:

SELECT FORMAT(GETDATE(), 'yyyy-MM-dd 00:00:00.000')


4

在SQL Server 2000上

CAST(
(
    STR( YEAR( GETDATE() ) ) + '/' +
    STR( MONTH( GETDATE() ) ) + '/' +
    STR( DAY( GETDATE() ) )
)
AS DATETIME)


3

您可以将以下用于日期部分并格式化日期:

DATENAME =>返回代表指定日期的指定日期部分的字符串

DATEADD =>该DATEPART()函数用于返回日期/时间的单个部分,例如年,月,日,小时,分钟等。

DATEPART =>返回一个整数,该整数表示指定日期的指定日期部分。

CONVERT()=>该CONVERT()函数是将一个数据类型的表达式转换为另一种数据类型的通用函数。该 CONVERT()功能可用于显示不同格式的日期/时间数据。

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.