将日期和时间合并(连接)成一个日期时间。

34

在使用SQL Server 2008时,这个查询非常有效:

select CAST(CollectionDate as DATE), CAST(CollectionTime as TIME)
from field

给我两列,就像这样:

2013-01-25  18:53:00.0000000
2013-01-25  18:53:00.0000000
2013-01-25  18:53:00.0000000
2013-01-25  18:53:00.0000000
    .
    .
    .

我正在尝试使用加号将它们组合成单个日期时间,就像这样:

select CAST(CollectionDate as DATE) + CAST(CollectionTime as TIME)
from field

我已经查看了大约十个网站,包括这个网站上的答案(像这个),他们都似乎同意加号应该起作用,但是我却收到了错误信息:

Msg 8117, Level 16, State 1, Line 1
Operand data type date is invalid for add operator.

所有字段都是非零且非空的。我还尝试过使用CONVERT函数并尝试将这些结果转换为varchars,但遇到相同的问题。这不可能难成我这样子吧。

可以有人告诉我为什么这样不起作用吗?谢谢任何帮助。


1
每列的原始数据类型是什么?如果它们是字符串,那么数据是如何存储的?(YYYY-MM-DD、YYYYMMDD等) - Lamak
实际上,我有一个跟你和@Aaron Bertrand相关的后续问题。如果在查询本身中进行CAST(或CONVERT)我的数据,那么基础数据存储为字符串或日期是否重要呢?我将其存储为datetime字段,但只是好奇。 - Stanton
@Stanton 当然重要。如果不需要,为什么要经过两个级别的转换/转换呢? - Aaron Bertrand
它们是日期时间? 是的,这很重要,你不能连接日期时间,这就是为什么我首先问数据类型的原因。 - Lamak
此外,被接受的答案假设CollectionDate上没有时间部分(即是一个带有00:00:00的日期)。如果不是这种情况,则会返回错误的结果。而第一个转换为datetime的转换是不必要的。 - Lamak
对于某些版本的SQL Server,如果使用CAST转换为DATETIME,则会失败。 转换为DATETIME2可以正常工作。 我现在使用了@Aaron Bertrand的答案,其中日期和时间都被转换为CHAR()。 - Kevin Swann
12个回答

63
假设底层数据类型是日期/时间/日期时间类型:
SELECT CONVERT(DATETIME, CONVERT(CHAR(8), CollectionDate, 112) 
  + ' ' + CONVERT(CHAR(8), CollectionTime, 108))
  FROM dbo.whatever;

这将把 CollectionDateCollectionTime 转换成字符序列,合并它们,然后将它们转换为一个 datetime

CONVERT 的参数包括数据类型 data_type、表达式 expression 和可选的 style(详见语法文档)。

日期和时间 style112 转换为 ISO yyyymmdd 格式。 style108 转换为 hh:mi:ss 格式。显然,两者都有 8 个字符长,这就是为什么 data_type 对于两者都是 CHAR(8)

所得到的合并字符序列格式为 yyyymmdd hh:mi:ss,然后转换为一个 datetime


Aaron,谢谢你的回复,如果你能对我上面的追问提供一些见解,我将不胜感激。 - Stanton
适用于sql-server-2012。干得好。 - FirebladeDan

26

简单的解决方案

SELECT CAST(CollectionDate as DATETIME) + CAST(CollectionTime as DATETIME)
FROM field

2
哇 - 我没想到这会起作用。完美! - Bonez024
1
@Bonex024 - 实际上它并不能“正确”地工作。它适用于OP给出的示例,因为没有小数秒。它可能对您也不起作用。DATETIME的分辨率为3.3毫秒,只能真正处理以0、3或7结尾的毫秒,因此您会立即失去分辨率。给它一个毫秒MOD(10)值为9的值,它会向上舍入到下一个时间段,这可能只是一毫秒远,也可能是一年,就像自2016年以来的23:59:59.999一样。隐式转换也会“失败”。 - Jeff Moden
谢谢Jeff。我还没有找到一种不需要字符串转换就能将日期和时间组合成DateTime的方法,大多数答案似乎都存在舍入问题,正如你所说的。我现在正在使用这个方法,并接受秒数保留两位小数... SELECT CONVERT(DATETIME, CONVERT(CHAR(8), CONVERT(DATE,'2023-01-31') , 112) + ' ' + CONVERT(CHAR(11), CONVERT(TIME,'23:59:59.999'))) ... 结果:2023-01-31 23:59:59.990 - AjV Jsy

9

一个更简单的解决方案(在 SQL Server 2014 SP1 CU6 上测试过)

代码:

DECLARE @Date date = SYSDATETIME();

DECLARE @Time time(0) = SYSDATETIME();

SELECT CAST(CONCAT(@Date, ' ', @Time) AS datetime2(0));

如果有一个特定日期和特定时间字段的表格,这种方法也可以使用。我经常使用这种方法,因为我们的供应商数据将日期和时间分开使用。


7
将它转换成datetime类型:
select CAST(CollectionDate as DATETIME) + CAST(CollectionTime as TIME)
from field

这适用于SQL Server 2008 R2。

如果出于某种原因,您想确保第一部分没有时间组件,则首先将字段转换为日期,然后再转换回datetime


4
402号消息,级别16,状态1,第1行 - 日期时间类型和时间类型在加法运算符中不兼容。 - Aaron Bertrand
1
SQL Server 2012。所以,现在可能可以工作,但当他们升级时会出问题。 - Aaron Bertrand
奇怪。微软在处理日期/时间值的方式上引入了一个破坏性变化?我想知道这是否受到任何配置参数的影响。 - user47589
3
确实。我建议接受@AaronBertrand的答案。我的答案要么现在有缺陷,要么很快就会有缺陷。(已被采纳的答案可以更改吗?我从未尝试过。) - user47589
1
在SQL 17.9中,将日期字段和时间字段同时转换为DateTime类型并相加是完全可行的。 - PRMan
显示剩余3条评论

1

处理日期时,必须使用dateadd以获得更高的精度。

declare @a DATE = getdate()
declare @b time(7) = getdate()
select @b, @A, GETDATE(), DATEADD(day, DATEDIFF(day, 0, @a), cast(@b as datetime2(0)))

存在一个四舍五入问题。select DATEADD(day, DATEDIFF(day, 0, '2023-01-01'), cast('23:59:59.999' as datetime2(0)))结果:2023-01-02 00:00:00 - AjV Jsy

1
DECLARE @ADate Date, @ATime Time, @ADateTime Datetime

SELECT @ADate = '2010-02-20', @ATime = '18:53:00.0000000'

SET @ADateTime = CAST   (
    CONVERT(Varchar(10), @ADate, 112) + ' ' +   
    CONVERT(Varchar(8), @ATime) AS DateTime)

SELECT @ADateTime [A nice datetime :)]

这将为您呈现一个有效的结果。

1

解决方案(1):日期时间算术

给定@myDate,它可以是可以转换为DATE的任何内容,和@myTime,它可以是可以转换为TIME的任何内容,在SQL Server 2014+开始,这个方法可以很好地工作,而且不涉及字符串操作:

CAST(CAST(@myDate as DATE) AS DATETIME) + CAST(CAST(@myTime as TIME) as DATETIME)

您可以使用以下方式进行验证:

SELECT  GETDATE(), 
        CAST(CAST(GETDATE() as DATE) AS DATETIME) + CAST(CAST(GETDATE() as TIME) as DATETIME)

解决方案(2):字符串操作

SELECT  GETDATE(), 
        CONVERT(DATETIME, CONVERT(CHAR(8), GETDATE(), 112) + ' ' + CONVERT(CHAR(8), GETDATE(), 108))

然而,解决方案(1)不仅比解决方案(2)快2-3倍,而且还保留了微秒部分。
请参见 SQL Fiddle,了解使用日期算术的 解决方案(1) 与涉及字符串操作的 解决方案(2)

1
这绝对是就精度和处理效率而言最好的答案。 - DatumPoint

-1

这在SQL 2008和2012中适用于生成datetime2:

declare @date date = current_timestamp;
declare @time time = current_timestamp;

select 
@date as date
,@time as time
,cast(@date as datetime) + cast(@time as datetime) as datetime
,cast(@time as datetime2) as timeAsDateTime2
,dateadd(dayofyear,datepart(dayofyear,@date) - 1,dateadd(year,datepart(year,@date) - 1900,cast(@time as datetime2))) as datetime2;

-1
drop table test

create table test(
    CollectionDate date NULL,
    CollectionTime  [time](0) NULL,
    CollectionDateTime as (isnull(convert(datetime,CollectionDate)+convert(datetime,CollectionTime),CollectionDate))
-- if CollectionDate is datetime no need to convert it above
)

insert test (CollectionDate, CollectionTime)
values ('2013-12-10', '22:51:19.227'),
       ('2013-12-10', null),
       (null, '22:51:19.227')

select * from test

CollectionDate  CollectionTime  CollectionDateTime
2013-12-10      22:51:19        2013-12-10 22:51:19.000
2013-12-10      NULL            2013-12-10 00:00:00.000
NULL            22:51:19        NULL

-1

我正在使用 SQL Server 2016,myDatemyTime 字段都是字符串。下面的 T-SQL 语句可以将它们拼接为datetime

select cast((myDate + ' ' + myTime) as datetime) from myTable

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