234

In an extract I am dealing with, I have 2 datetime columns. One column stores the dates and another the times as shown.

How can I query the table to combine these two fields into 1 column of type datetime?

Dates

2009-03-12 00:00:00.000
2009-03-26 00:00:00.000
2009-03-26 00:00:00.000

Times

1899-12-30 12:30:00.000
1899-12-30 10:00:00.000
1899-12-30 10:00:00.000
ErikE
  • 48,881
  • 23
  • 151
  • 196
Jon Winstanley
  • 23,010
  • 22
  • 73
  • 116

20 Answers20

277

You can simply add the two.

  • if the Time part of your Date column is always zero
  • and the Date part of your Time column is also always zero (base date: January 1, 1900)

Adding them returns the correct result.

SELECT Combined = MyDate + MyTime FROM MyTable

Rationale (kudos to ErikE/dnolan)

It works like this due to the way the date is stored as two 4-byte Integers with the left 4-bytes being the date and the right 4-bytes being the time. Its like doing $0001 0000 + $0000 0001 = $0001 0001

Edit regarding new SQL Server 2008 types

Date and Time are types introduced in SQL Server 2008. If you insist on adding, you can use Combined = CAST(MyDate AS DATETIME) + CAST(MyTime AS DATETIME)

Edit2 regarding loss of precision in SQL Server 2008 and up (kudos to Martin Smith)

Have a look at How to combine date and time to datetime2 in SQL Server? to prevent loss of precision using SQL Server 2008 and up.

Liam
  • 27,717
  • 28
  • 128
  • 190
Lieven Keersmaekers
  • 57,207
  • 13
  • 112
  • 146
  • 2
    @Jon, It's true so long as the time element of the date column and the date element of the time column are both zero. – LukeH Mar 31 '09 at 09:02
  • it does this due to the way the date is stored as a float, with the left part being the date and the right of the decimal being the time, so its like doing 1.0 + 0.5 = 1.5 – dnolan Oct 20 '09 at 10:01
  • I do this and my date is off (early) by 2 days, but the time is correct? – CodeGrue Mar 24 '10 at 19:09
  • 1
    You are most likely experiencing what is desribed here http://groups.google.be/group/borland.public.delphi.database.sqlservers/browse_frm/thread/b2e07edb46f63cba/1ab62659d8be3135?lnk=st&q=2+sqlserver+com+datetime+group%3A*borland*+author%3A*teamb*#1ab62659d8be3135 – Lieven Keersmaekers Mar 25 '10 at 07:45
  • This isn't working for me, using SQL Server 2008 r2, with my Date column as a `date` type, and my Time column as a `time(7)` type – STW Feb 29 '12 at 13:26
  • @STW - Date and Time are types introduced in SQL Server 2008. If you insist on adding, you can use `Combined = CAST(MyDate AS DATETIME) + CAST(MyTime AS DATETIME)` – Lieven Keersmaekers Feb 29 '12 at 13:32
  • Casting to DATETIME won't work if your date column is earlier than 1/1/1753, and you can't use the add operator with the DATETIME2 type. If you need to support dates that far back, you'll need to use a combination of DateAdd and DateDiff: `Combined = DateAdd(minute, DateDiff(minute, '00:00', MyTime), Convert(datetime2, MyDate))` – Richard Deeming Sep 20 '12 at 11:42
  • While the addition of datetime/time worked without CAST in SQL 2008/2008R2, it no longer works in SQL 2012, it will produce an error: "The data types datetime and time are incompatible in the add operator" – Kevin Dahl Oct 29 '12 at 19:42
  • 2
    The "zero" date in SQL Server is `1900-01-01`, no? – Andriy M Jan 16 '13 at 08:05
  • 1
    When i tried this I did not need to cast the 'time' value to datetime. In other words you can do: datetime + time – Sam Mar 07 '13 at 05:55
  • 2
    @dnolan dates in SQL server are NOT stored as `float`. Where on earth did you learn this? They are stored as *integers*: the date portion is the number of days since an anchor date, and the time portion is the number of "ticks" since midnight, ticks being defined as 1/300 s for `datetime` and more precise for `time` and `datetime2`. – ErikE Apr 15 '13 at 21:39
  • 1
    @LievenKeersmaekers Please see my above comment. Please fix your answer. – ErikE Apr 15 '13 at 21:40
  • @ErikE - I loved the simplicity of dnolan's comment explaining what was happening but you are right, it's not a float. I have tried to ammend the answer without losing *(too much)* of this simplicity. Feel free to edit the answer further if you feel it's still inadequate and thanks for the heads up. – Lieven Keersmaekers Apr 16 '13 at 16:44
  • 1
    I was going to fix your post, but there are more problems. The zero date in SQL Server is not `1899-12-30` but `1900-01-01`, two days later. So your post is factually incorrect for SQL Server: the OP's comment about 2 days off was spot on and the commented answer incorrect: He needs to add two days to account for the 2-day difference between anchor dates. Try it: `select convert(datetime, '2009-03-12 00:00:00.000') + convert(datetime, '1899-12-30 12:30:00.000')`. – ErikE Apr 16 '13 at 19:24
  • 1
    @ErikE - Correct, the [base date](http://msdn.microsoft.com/en-us/library/ms187819(v=sql.90).aspx) is indeed 1900-01-01. It amazes me that no-one noticed earlier. Most likely because it is a working solution but with an wrong explanation. – Lieven Keersmaekers Apr 17 '13 at 05:24
  • @ErikE - That does bring up the question as to why OP is showing `1899-12-30` for the time only columns. – Lieven Keersmaekers Apr 17 '13 at 05:29
  • 1
    They probably came from another DBMS, perhaps MS Access. Or from Excel. Those two have an anchor date a day or two earlier. Or the DBMS in your link above. – ErikE Apr 17 '13 at 09:04
  • @ErikE - actually, Andriy already corrected me about the base date to wich I replied but the penny didn't drop for me then that I should alter the answer. I don't know what I was drinking back then but it must have been something strong :) – Lieven Keersmaekers Apr 17 '13 at 09:49
  • Your SQL Server 2008 version loses precision for `time(3) - time(7)` – Martin Smith Oct 14 '13 at 10:33
  • @MartinSmith - I haven't tested it but wouldn't `CAST AS DATETIME2(7)` resolve that? – Lieven Keersmaekers Oct 14 '13 at 11:56
  • No. `+` isn't implemented for adding any of the new datatypes. [One method is here](http://dba.stackexchange.com/questions/51440/how-to-combine-date-and-time-to-datetime2-in-sql-server/51443#51443) – Martin Smith Oct 14 '13 at 12:00
  • I can't go blindly copying your answer to this one but I'll edit the answer and refer to yours for SQL Server 2008 and up. – Lieven Keersmaekers Oct 14 '13 at 12:08
  • 1
    It was @ypercube's answer in fact! This answer is high in the search results for "combine date and time sql server" so probably quite a few people using the newer datatypes will be coming across it. – Martin Smith Oct 14 '13 at 12:16
  • @ErikE: It is correct, it is mostly coming from Excel. I got into same issue in while importing a excel file. Seems like excel [doesn't likes 1/1/1900](http://bit.ly/1EiG2HJ). So if there is a time column in excel and you are importing and using OLEDB you will get 1899/12/30. While the date (the invoice date, transaction date or whatever) could be in a different column entirely. – Razort4x Apr 20 '15 at 07:35
  • @Liam: is there a way to accomplish this same thing in mysql? – Andrelope Oct 14 '20 at 19:09
141

If the time element of your date column and the date element of your time column are both zero then Lieven's answer is what you need. If you can't guarantee that will always be the case then it becomes slightly more complicated:

SELECT DATEADD(day, 0, DATEDIFF(day, 0, your_date_column)) +
    DATEADD(day, 0 - DATEDIFF(day, 0, your_time_column), your_time_column)
FROM your_table
Community
  • 1
  • 1
LukeH
  • 263,068
  • 57
  • 365
  • 409
  • Thanks for the answer Luke. Luckily, in this case I can guarantee other items are always zero, I think the 2 fields may even be 1 on the other side the 3rd party code which does the extract for us. – Jon Winstanley Mar 31 '09 at 13:12
  • 6
    I had the same problem as the OP except I know the unneeded parts are never zero. This has therefore been immeasurably useful, if I could vote you up twice I would! –  May 22 '09 at 15:53
  • This saved me! I was converting both to chars and then concating and then back to DATETIME, but then I couldn't index it, because SQL said it was non-deterministic. This apparently IS deterministic!!! THANK !!! YOU !!! – eidylon Mar 14 '12 at 18:40
  • 4
    Your SQL Server 2008 version doesn't work. `The data types datetime and time are incompatible in the add operator.` – Martin Smith Oct 14 '13 at 10:31
  • @Martin: I've removed the broken SQL2008 version. – LukeH Mar 10 '15 at 10:49
  • Great solution for MS Dynamics NAV default "zero" date of '1754-01-01'. Exactly what I needed. Great Job LukeH – jediCouncilor Dec 18 '15 at 21:20
  • 1
    I would also suggest including an `ISNULL([expr],0)` expression **in case you encounter a null value** in either the date or time. (Otherwise your combined DATETIME will be null.) – AdamsTips Jan 31 '18 at 15:17
  • My columns 'your_date_column' and 'your_time_column' were datetime2, so I casted the two addends to datetime to make it work: `SELECT CAST(DATEADD(day, 0, DATEDIFF(day, 0, your_date_column)) AS DATETIME) + CAST(DATEADD(day, 0 - DATEDIFF(day, 0, your_time_column), your_time_column) AS DATETIME) FROM your_table` – Njal Jan 06 '20 at 03:51
31

This is an alternative solution without any char conversions:

DATEADD(ms, DATEDIFF(ms, '00:00:00', [Time]), CONVERT(DATETIME, [Date]))

You will only get milliseconds accuracy this way, but that would normally be OK. I have tested this in SQL Server 2008.

John Conde
  • 217,595
  • 99
  • 455
  • 496
Jojje
  • 763
  • 1
  • 8
  • 10
  • Has a rounding up issue? Try `select DATEADD(ms, DATEDIFF(ms,'00:00:00','23:59:59.999'), '2023-01-01' )` and it rounds to 2023-01-02 00:00:00.000 – AjV Jsy Mar 30 '23 at 10:28
16

This worked for me

CAST(Tbl.date as DATETIME) + CAST(Tbl.TimeFrom AS TIME)

(on SQL 2008 R2)

biso
  • 590
  • 1
  • 4
  • 13
  • 1
    Worked great in SQL Server 2008. – Tobias Jan 21 '15 at 07:34
  • 10
    I get The data types datetime and time are incompatible in the add operator. error on SQL Server 2012 – Devin Prejean May 18 '16 at 15:45
  • 4
    SQL 2012 The data types datetime and time are incompatible in the add operator – Raffaeu Jun 26 '16 at 20:52
  • 4
    This no longer works in SQL Server 2012 and above (breaking change). See here for details: https://social.msdn.microsoft.com/forums/azure/en-US/8c163ac8-dae7-4d95-ad8f-3e4b52c3965d/difference-in-datetime-and-time-arithmetic-in-sql-azure-vs-sql-server-2008-r2?forum=ssdsgetstarted – Heinzi Feb 20 '18 at 09:22
  • It doesn't work on SQL Server 2019 (15) either. – Pato Nov 26 '21 at 00:52
  • Works great for me. For me I didn't need to Cast my date as DateTime because it already was a Datetime. I think your way is more reliable than the other method of [Date] + [TIME] + 2. That other way depends on the Time column always having a year/MM/dd of 1899-12-30 which might not always be the case if the data was imported from another SQLServer or another database which it defaults the date to 1900-01-01 as the first year/month/day it can support. I am using SQL Server 2014 for this. But I also use SQL Server 2019 and it should work for that too. – John Foll Jan 28 '22 at 16:47
10

If you're not using SQL Server 2008 (i.e. you only have a DateTime data type), you can use the following (admittedly rough and ready) TSQL to achieve what you want:

DECLARE @DateOnly AS datetime
DECLARE @TimeOnly AS datetime 

SET @DateOnly = '07 aug 2009 00:00:00'
SET @TimeOnly = '01 jan 1899 10:11:23'


-- Gives Date Only.
SELECT DATEADD(dd, 0, DATEDIFF(dd, 0, @DateOnly))

-- Gives Time Only.
SELECT DATEADD(Day, -DATEDIFF(Day, 0, @TimeOnly), @TimeOnly)

-- Concatenates Date and Time parts.
SELECT
CAST(
    DATEADD(dd, 0, DATEDIFF(dd, 0, @DateOnly)) + ' ' +
    DATEADD(Day, -DATEDIFF(Day, 0, @TimeOnly), @TimeOnly)           
as datetime)

It's rough and ready, but it works!

CraigTP
  • 44,143
  • 8
  • 72
  • 99
9
  1. If both of your fields are datetime then simply adding those will work.

    eg:

    Declare @d datetime, @t datetime
    set @d = '2009-03-12 00:00:00.000';
    set @t = '1899-12-30 12:30:00.000';
    select @d + @t
    
  2. If you used Date & Time datatype then just cast the time to datetime

    eg:

    Declare @d date, @t time
    set @d = '2009-03-12';
    set @t = '12:30:00.000';
    select @d + cast(@t as datetime)
    
sth
  • 222,467
  • 53
  • 283
  • 367
5

This was my solution which ignores the date value of the time column

CAST(Tbl.date as DATETIME) + CAST(CAST(Tbl.TimeFrom AS TIME) as DATETIME)

Hope this helps others

CFreitas
  • 1,647
  • 20
  • 29
Jarhn Swift
  • 51
  • 1
  • 1
4

Convert both field into DATETIME :

SELECT CAST(@DateField as DATETIME) + CAST(@TimeField AS DATETIME)

and if you're using Getdate() use this first:

DECLARE @FechaActual DATETIME = CONVERT(DATE, GETDATE());
SELECT CAST(@FechaActual as DATETIME) + CAST(@HoraInicioTurno AS DATETIME)
Sᴀᴍ Onᴇᴌᴀ
  • 8,218
  • 8
  • 36
  • 58
3

Convert the first date stored in a datetime field to a string, then convert the time stored in a datetime field to string, append the two and convert back to a datetime field all using known conversion formats.

Convert(datetime, Convert(char(10), MYDATETIMEFIELD, 103) + ' ' + Convert(char(8), MYTIMEFIELD, 108), 103) 
sth
  • 222,467
  • 53
  • 283
  • 367
SPE109
  • 2,911
  • 1
  • 19
  • 16
  • 3
    Converting to string is slower than dateadd. http://stackoverflow.com/questions/2775/whats-the-best-way-to-remove-the-time-portion-of-a-datetime-value-sql-server/3696991#3696991 – ErikE Nov 24 '10 at 22:06
2

I had many errors as stated above so I did it like this

try_parse(concat(convert(date,Arrival_date),' ',arrival_time) as datetime) AS ArrivalDateTime

It worked for me.

Mr Mush
  • 1,538
  • 3
  • 25
  • 38
Tom
  • 21
  • 1
2

Finding this works for two dates where you want time from one and date from the other:

declare @Time as datetime = '2021-11-19 12:34'
declare @Date as datetime = '2021-10-10'
SELECT @time + datediff(day, @Time, @Date)
cloudsafe
  • 2,444
  • 1
  • 8
  • 24
2
DECLARE @Dates table ([Date] datetime);
DECLARE @Times table ([Time] datetime);

INSERT INTO @Dates VALUES('2009-03-12 00:00:00.000');
INSERT INTO @Dates VALUES('2009-03-26 00:00:00.000');
INSERT INTO @Dates VALUES('2009-03-30 00:00:00.000');

INSERT INTO @Times VALUES('1899-12-30 12:30:00.000');
INSERT INTO @Times VALUES('1899-12-30 10:00:00.000');
INSERT INTO @Times VALUES('1899-12-30 10:00:00.000');

WITH Dates (ID, [Date])
AS (
    SELECT ROW_NUMBER() OVER (ORDER BY [Date]), [Date] FROM @Dates
), Times (ID, [Time])
AS (
    SELECT ROW_NUMBER() OVER (ORDER BY [Time]), [Time] FROM @Times
)
SELECT Dates.[Date] + Times.[Time] FROM Dates
    JOIN Times ON Times.ID = Dates.ID

Prints:

2009-03-12 10:00:00.000
2009-03-26 10:00:00.000
2009-03-30 12:30:00.000
Konstantin Tarkus
  • 37,618
  • 14
  • 135
  • 121
1

To combine date from a datetime column and time from another datetime column this is the best fastest solution for you:

select cast(cast(DateColumn as date) as datetime) + cast(TimeColumn as datetime) from YourTable
1

SELECT CAST(CAST(@DateField As Date) As DateTime) + CAST(CAST(@TimeField As Time) As DateTime)

Shah
  • 21
  • 1
1
select s.SalesID from SalesTbl s 
        where cast(cast(s.SaleDate  as date) as datetime) + cast(cast(s.SaleCreatedDate as time) as datetime) between @FromDate and @ToDate
Arun Prasad E S
  • 9,489
  • 8
  • 74
  • 87
0

Another way is to use CONCATand CAST, be aware, that you need to use DATETIME2(x) to make it work. You can set x to anything between 0-7 7 meaning no precision loss.

DECLARE @date date = '2018-03-12'
DECLARE @time time = '07:00:00.0000000'
SELECT CAST(CONCAT(@date, ' ', @time) AS DATETIME2(7))

Returns 2018-03-12 07:00:00.0000000

Tested on SQL Server 14

LuckyLikey
  • 3,504
  • 1
  • 31
  • 54
0

simply concatenate both , but cast them first as below

select cast(concat(Cast(DateField as varchar), ' ', Cast(TimeField as varchar)) as datetime) as DateWithTime from TableName;
Ali
  • 1,080
  • 16
  • 22
0

The existing answers do not address the datetime2 datatype so I will add mine:

Assuming that you want to add a time value to a datetime2 value where:

  • The datetime2 value could contain non-zero time component and/or fractional seconds
  • The time value could contain the value 23:59:59.9999999 which is 86,399.9999999 seconds, 86,399,999,999.9 microseconds or 86,399,999,999,900 nanoseconds¹

Due to the limitations of dateadd function¹ you must add them in two steps:

  • Convert the time value to seconds and use dateadd(second, ...)
  • Extract the nanoseconds from the time value and use dateadd(nanosecond, ...) to add them to the date calculated above
declare @dv datetime2 = '2000-01-01 12:34:56.7890123';
declare @tv time = '23:59:59.9999999';
select dateadd(
    nanosecond,
    datepart(nanosecond, @tv),
    dateadd(
        second,
        datepart(hour, @tv) * 60 * 60 + datepart(minute, @tv) * 60 + datepart(second, @tv),
        @dv
    )
);
-- 2000-01-02 12:34:56.7890122

¹ Nanosecond values might not fit in int datatype which dateadd function expects.

Salman A
  • 262,204
  • 82
  • 430
  • 521
-1
SELECT CAST(your_date_column AS date) + CAST(your_time_column AS datetime) FROM your_table

Works like a charm

Sᴀᴍ Onᴇᴌᴀ
  • 8,218
  • 8
  • 36
  • 58
-2

I ran into similar situation where I had to merge Date and Time fields to DateTime field. None of the above mentioned solution work, specially adding two fields as the data type for addition of these 2 fields is not same.

I created below solution, where I added hour and then minute part to the date. This worked beautifully for me. Please check it out and do let me know if you get into any issues.

;with tbl as ( select StatusTime = '12/30/1899 5:17:00 PM', StatusDate = '7/24/2019 12:00:00 AM' ) select DATEADD(MI, DATEPART(MINUTE,CAST(tbl.StatusTime AS TIME)),DATEADD(HH, DATEPART(HOUR,CAST(tbl.StatusTime AS TIME)), CAST(tbl.StatusDate as DATETIME))) from tbl

Result: 2019-07-24 17:17:00.000