如何在SQL Server中将日期和时间合并到datetime2?


48

鉴于以下组件

DECLARE @D DATE = '2013-10-13'
DECLARE @T TIME(7) = '23:59:59.9999999'

将它们结合起来以产生DATETIME2(7)具有价值的结果的最佳方法是'2013-10-13 23:59:59.9999999'什么?

下面列出了一些无效的内容。


SELECT @D + @T 

操作数数据类型日期对于加法运算符无效。


SELECT CAST(@D AS DATETIME2(7)) + @T 

操作数数据类型datetime2对于加法运算符无效。


SELECT DATEADD(NANOSECOND,DATEDIFF(NANOSECOND,CAST('00:00:00.0000000' AS TIME),@T),@D)

datediff函数导致溢出。分隔两个日期/时间实例的日期部分的数量太大。尝试将datediff与不太精确的datepart一起使用。

*使用可以避免在Azure SQL数据库和SQL Server 2016中发生溢出DATEDIFF_BIG


SELECT CAST(@D AS DATETIME) + @T 

数据类型datetime和time在add运算符中不兼容。


SELECT CAST(@D AS DATETIME) + CAST(@T AS DATETIME)

返回结果但失去精度 2013-10-13 23:59:59.997

Answers:


49

这似乎可以正常工作并保持精度:

SELECT DATEADD(day, DATEDIFF(day,'19000101',@D), CAST(@T AS DATETIME2(7)))

CASTDATETIME2(7)转换TIME(7)价值(@T)到DATETIME2其中的日期部分'1900-01-01',这是日期和时间类型的默认值(见datetime2和注释*CASTCONVERT页面在MSDN。)

* ...当仅表示日期或仅时间部分的字符数据转换为datetime或smalldatetime数据类型时,未指定的时间部分设置为00:00:00.000,未指定的日期部分设置为1900-01- 01

DATEADD()DATEDIFF()功能照料休息,即在天之间将差异1900-01-01DATE价值(@D)。

在以下位置进行测试:SQL小提琴


@Quandary所注意到的,SQL Server认为上述表达式不是确定性的。如果我们要使用确定性表达式,例如因为要用于PERSISTED列,则需要用或替换'19000101'**0CONVERT(DATE, '19000101', 112)

CREATE TABLE date_time
( d DATE NOT NULL,
  t TIME(7) NOT NULL,
  dt AS DATEADD(day, 
                DATEDIFF(day, CONVERT(DATE, '19000101', 112), d), 
                CAST(t AS DATETIME2(7))
               ) PERSISTED
) ;

**:DATEDIFF(day, '19000101', d)不是确定性的,因为它会隐式地将字符串转换为字符串,DATETIME并且从字符串到日期时间的转换只有在使用特定样式时才是确定性的


8

我来晚了,但是这种方法虽然与@ypercube的答案类似,但是避免了使用任何字符串转换(比日期转换更昂贵)的需要,它是确定性的,并且如果MS更改了1900年1月1日的默认日期值(即使他们可能不会对此进行更改):

DECLARE @D DATE = SYSUTCDATETIME()
, @T TIME = SYSUTCDATETIME();

SELECT DATEADD(DAY, DATEDIFF(DAY, @T, @D), CONVERT(DATETIME2, @T));

原理是,通过将时间值转换为datetime2,然后转换为date,它将剥离时间并分配默认日期,然后使用datediff将datediff与日期值相加以获得要添加的天数,将时间转换为datetime2并添加天。


代替“ DATEDIFF(DAY,@T,@D)”,它应该是“ DATEDIFF(DAY,0,@D)”。结果是相同的,但有助于避免混淆。DateDiff(day,...)将参数强制转换为最小的int天数,因此@T始终转换为0。
Dennis Gorelik

5

对于SQL Server 2012及更高版本,具有DATETIME2FROMPARTS函数。它具有以下形式:

DATETIME2FROMPARTS(year, month, day, hour, minute, seconds, fractions, precision)

对于给定的样本数据,它变为

select Answer = DATETIME2FROMPARTS(2013, 10, 13, 23, 59, 59, 9999999, 7);

导致

Answer
---------------------------
2013-10-13 23:59:59.9999999

如果从时间数据类型或用于构造问题中样本值的文本开始,则可以使用DATEPART()获得零件。


0

不让您的第一个示例正常工作对SQL Server来说是非常愚蠢的,这似乎也很愚蠢,但是…

select convert(datetime2, convert(nvarchar(max), @d) + ' ' + convert(nvarchar(max), @t));

0
SELECT mydate=CAST(CAST(@D AS nvarchar(max)) + ' ' + 
                   CAST(@T AS nvarchar (max)) 
              AS DATETIME2);

5
你测试过了吗?它行得通吗?它受语言设置影响吗?
ypercubeᵀᴹ

0

我登陆这里时正在寻找其他东西。这个问题已经很老了,但是最近有一些评论和活动。以为我会分享一个非常简单的方法,该方法与@Atario给出的答案非常相似,但是要简短一些,有些可能会更易于阅读:

declare @d date = '2013-10-13'
declare @t time(7) = '23:59:59.9999999'

select cast(concat(@d, ' ', @t) as datetime2(7))

-3

您可以截断with转换为DATE进行截断,然后返回DATETIME以添加TIME

select CAST( cast(getdate() as date) as DATETIME)  + CAST(getdate() as TIME)

诀窍很好,但是并不能回答最上面的问题。
user259412 '18
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.