Incompatibility convert DateTime between SQL Server 2012 and SQL Server 2019 - sql-server

I have a stored procedure running fine in SQL Server 2012, but when I run it in SQL Server 2019, I got this error message:
The data types datetime and time are incompatible in the add operator.
This is the line of the error :
(CONVERT(datetime, shfts.Date) + SftpStartTime) AS SftStartDateTime,
CASE
WHEN ((CONVERT(datetime, shfts.Date) +SftpEndTime)
> (CONVERT(datetime, shfts.Date) + SftpStartTime))

The following (datetime + time) does work in databases with compatibility level 100 (SQL Server 2008) but not in databases with later compatibility mode
SELECT {d '2000-01-01'} + CAST('11:59' AS time)
The execution plan for the above has an CONVERT_IMPLICIT from time to datetime that no longer happens here.
Explicitly casting the second operand to datetime (as below) does work but is a bit icky and won't preserve all the precision possible of time (will lose any precision beyond milliseconds and round any millisecond component to 0, 3 or 7). Nonetheless this is the same as the 2008 compat would give you (and is unlikely to be a concern for shift start/end times).
It has the same results as adding a timespan to a datetime would (including possible rollover to next day if the datetime portion is not at midnight).
SELECT {d '2000-01-01'} + CAST(CAST('11:59' AS time) AS datetime)
A less icky method is
SELECT DATEADD(day, DATEDIFF(day,'19000101',{d '2000-01-01'}), CAST(CAST('11:59' AS time) AS DATETIME2(7)))

Related

SQL getdate() - not the same in one statement

The getDate() statement always returns the same value anywhere in one statement.
However, in one SQL Server 2017, I'm seeing otherwise.
To set this up, create a table and put two rows into it:
CREATE TABLE Test
(
TestDate datetime2(0) NULL,
OtherValue varchar(5) NULL
)
INSERT INTO Test (OtherValue) VALUES ('x')
INSERT INTO Test (OtherValue) VALUES ('x')
Then run this query a number of times:
SELECT
CASE
WHEN GETDATE() < COALESCE(TestDate, GETDATE())
THEN 'less'
WHEN GETDATE() > COALESCE(TestDate, GETDATE())
THEN 'greater'
ELSE 'same'
END [Compare]
FROM
Test
Both rows always return matching results.
When I do this in SQL Server 2008 R2 (v10.50) and other SQL Server 2017 machines, the result is always 'same'.
However, on one of my SQL Server 2017 instances, it varies randomly between 'same', 'less' and 'greater':
Why is this happening? Is there a server setting that can cause this?
Edit:
Using SYSDATETIME in place of GETDATE works as expected on the 'bad' server, always returning 'same'.
Edit #2:
If I test GETDATE as above on a column defined as DATETIME (which is what GETDATE() generates), then it works as expected. So it seems to be related to converting between DATETIME and DATETIME2.
Interesting enough question.
The behaviour in your example can be explaned by the following:
Since SQL Server 2016, datetime rounding have been changed. In short: since 2016 SQL Server, value doesn't round before comparison and comparison executes with raw value. Before 2016 SQL Server, value is rounded and then compare.
By default, comparison datetime and datetime2 performs with conversion datetime to datetime2(7). You can see that in execution plan.
datetime variable with 3 at the end - for example .003 - gets converted in .0033333. 007 gets converted in .0066667.
And the most interest part: nanoseconds. During comparison SQL Server uses 8 (or more!) digits in fractional part. I just show two examples to explane.
DECLARE #DateTime datetime = '2016-01-01T00:00:00.003';
DECLARE #DateTime2 datetime2(7) = #DateTime;
select datepart(NANOSECOND,#DateTime) as "DateTimeRes",
datepart(nanosecond,#DateTime2) as "DateTime2Res"
go
DECLARE #DateTime datetime = '2016-01-01T00:00:00.007';
DECLARE #DateTime2 datetime2(7) = #DateTime;
select datepart(NANOSECOND,#DateTime) as "DateTimeRes",
datepart(nanosecond,#DateTime2) as "DateTime2Res"
Results:
+-------------+--------------+
| DateTimeRes | DateTime2Res |
+-------------+--------------+
| 3333333 | 3333300 |
+-------------+--------------+
+-------------+--------------+
| DateTimeRes | DateTime2Res |
+-------------+--------------+
| 6666666 | 6666670 |
+-------------+--------------+
I took it all from this article.
Also, there is a similar question on SO.
I believe this behaviour is independent of your server repformance (virtual machine or etc).
Good luck!
Turns out the behaviour of getdate changed from SQL 2000 to SQL 2005.
See https://stackoverflow.com/a/3620119/32429 explaining the old behaviour:
In practice, GETDATE() is only evaluated once for each expression
where it is used -- at execution time rather than compile time.
However, Microsoft puts rand() and getdate() into a special category,
called non-deterministic runtime constant functions.
and the following discussion:
In SQL 2000 if you did something like this
INSERT INTO tbl (fields, LOADDATE) SELECT fields, GETDATE() FROM tblb
you would get the same date/time for all records inserted.
This same command In SQL 2005, reruns GETDATE() for every single
record selected from tblb and gives you potentially unique values for
each record. Also causes HUGE performance problems if you are
inserting say, 17 million rows at a time.
This has caused me many a headache, as we use this code to do batch
date/times in many tables. This was a very simple way to back out a
"batch" of transactions, because everything had the same date/time.
Now in 2005, that is not true.

Excel incorrectly converts Date into Int

I'm pulling the data from SQL database. I have a couple columns with date which need to be converted into Int type, but when I do this the date changes (-2 days). I tried Cast and Convert and it's always the same.
Converting to other type works fine and returns the correct date, but doesn't work for me. I need only the date part from datetime and it needs to be recognised as a date by Excel.
Why is this happening? Any ideas how to get it sorted?
I'm using the following query:
SELECT wotype3, CONVERT(INT,wo_date2 ,103), CAST(duedate AS int) FROM Tasks WHERE
duedate > DATEADD(DAY,1, GETDATE())
AND wo_date2>0
AND wo_date2<DATEADD(WEEK,3,GETDATE())
ORDER BY wotype3
I've had big problems with this, checking my SQL Server's calculation results with "expected results" which a user had created using Excel.
We had discrepancies just because of this 2-day date difference.
Why does it happen ?
Two reasons:
SQL Server uses a zero-based date count from Jan 1 1900, but Excel uses a 1-based date count from Jan 1 1900.
Excel has a bug in it (gasp!) which makes it think that the year 1900 was a leap year. It wasn't. SQL Server correctly refuses to let you have a date value containing "29-Feb-1900".
Combine these two discrepancies, and this is why all dates, from March 1 1900 onwards, are always 2-days out.
Apparently, this Excel bug is a known issue, to keep it in line with Lotus 1-2-3.
The Intentional Date Bug
Microsoft's own explanation
From now on, I think I'll justify bugs in my code with the same excuse.
;-)
For SQL Server 2008 and above, you can use the DATE datatype.
declare #dt datetime = '12/24/2013 10:45 PM' -- some date for example
SELECT #dt as OriginalDateTime, CAST(#dt as DATE) as OnlyDate
For versions prior to SQL Server 2008, you would need to truncate the time part using one or the other functions. Here is one way to do that:
declare #dt datetime = '12/24/2013 10:45 PM' -- some date for example
SELECT #dt as OriginalDateTime, CAST(FLOOR(CAST(#dt AS FLOAT)) as DATETIME) as OnlyDate

Datetime function to get specific dates 12:00AM time

if any date time value provided to sql server can i get it's midnight value with some function in sql server.. for example if i provide 2013/07/03 01:34AM , i want to get it to 2013/07/03 12:00 AM.Is there a way to do it?
SQL Server 2008+
SELECT CAST(CAST('2013/07/03 01:34AM' AS date) AS datetime)
For older versions, see this Best approach to remove time part of datetime in SQL Server Never use anything that requires float or int or varchar conversions
This should give you what you need:
SELECT DATEADD(DAY, DATEDIFF(DAY, 0, InputDateField), 0)
Should be slightly quicker than cast:
Most efficient way in SQL Server to get date from date+time?

what is the best way to insert only datepart of system date into SQL Server

I'm currently using
Convert(varchar, Getdate(), 101)
to insert only date part of system date into one of my sql server database tables.
my question is: is it the right way to do that or is there any other better method to do it?
I don't understand why you're converting the GETDATE() output (which is DATETIME already) to a VARCHAR and then SQL Server would convert it back to DATETIME upon inserting it again.
Just use:
INSERT INTO dbo.YourTable(SomeDateTimeColumn)
VALUES(GETDATE())
If you're doing that conversion to get rid of the time portion of the DATETIME, you should better:
use the DATE datatype (available in SQL Server 2008 and newer) to store only the DATE (no time)
if you're using SQL Server 2005 or earlier, use this conversion instead - should be much more efficient than two conversions!
INSERT INTO dbo.YourTable(SomeDateTimeColumn)
VALUES(DATEADD(dd, DATEDIFF(dd, 0, GETDATE()), 0))
Update: did some performance testing, and in this particular case, it seems the amount of work that SQL Server needs to do is really the same - regardless of whether you're using the convert to varchar stripping the time and back to datetime approach that you already have, or whether you're using my get the number of days since date 0 approach. Doesn't seem to make a difference in the end.
The BEST solution however would still be: if you only need the date anyway - use a column of type DATE (in SQL Server 2008 and newer) and save yourself any conversions or manipulations of the GETDATE() output altogether.

Has date type changed in SQL Server 2008?

I am confused reading statements in "Why is 1899-12-30 the zero date in Access / SQL Server instead of 12/31?"
Was there date type in SQL Server before 2008 version? I cannot find.
In SQL Server 2008 zero date is 0001-01-01. Were there any date type before (in previous SQL Server versions) how is it backward compatible?
No. Prior to SQL Server 2008, there was only the datetime and smalldatetime types.
Data type...............Range..................................................................Accuracy
datetime..................January 1, 1753, through December 31, 9999.....3.33 milliseconds
smalldatetime..........January 1, 1900, through June 6, 2079............... 1 minute
Please see: Date and Time Data in SQL Server 2008, specifically the bit that says "Date/Time Data Types Introduced in SQL Server 2008"
In SQL Server datetime datatype the minimum date that can be stored is 1 Jan 1753.
However the datetimes are stored as numeric offsets to a base date of 1900-01-01 00:00:00.000
SELECT CAST(-0.25 AS DATETIME) /*1899-12-31 18:00:00.000*/
SELECT CAST(0 AS DATETIME) /*1900-01-01 00:00:00.000*/
SELECT CAST(0.25 AS DATETIME) /*1900-01-01 06:00:00.000*/
1899-12-30 has no significance in SQL Server.
SELECT CAST(CAST('1899-12-30' AS DATETIME) AS FLOAT) /*Returns -2*/

Resources