Strange datetime behavior in SQL Server - sql

declare #data datetime
set #data = '2011-01-01 23:59:59:999'
select #data
result is:
2011-01-02 00:00:00.000
Second example:
declare #data datetime
set #data = '2011-01-01 23:59:59:999'
select 1 where #data >= '2011-01-02 00:00:00:000'
result
1
My question is why and how to make it correct?
edit
problem is in sql server 2008

You have a precision problem. .999 is rounded up to .000.
.997 is as close to the next day as you can get.
declare #data datetime
set #data = '2011-01-01T23:59:59.997'
select #data
Have a look here at the section about "Rounding of datetime Fractional Second Precision"
http://msdn.microsoft.com/en-us/library/ms187819.aspx
If you are on SQL Server 2008 you can use datetime2(3) if you want a precision down to the millisecond.

You need to use more precise format - datetime2 (YYYY-MM-DD HH:MM:SS:XXXXXXX)
declare #data datetime2
set #data = '2011-01-01 23:59:59:999'
select 1 where #data >= '2011-01-02 00:00:00:000'

Related

SQL returning invalid results when comparing against 2 date ranges

As mentioned in the subject line, SQL is returning results which are not within the specific date range, here is my SQL snipped below:
DECLARE #StartDate DATETIME
,#EndDate DATETIME
SET #StartDate = '2017-03-04 00:50:00.000'
SET #EndDate = '2017-03-05 01:30:00.000
SELECT * FROM table (NOLOCK) WHERE CreatedOn BETWEEN #StartDate AND #EndDate
Partial Results
CreatedOn
2017-03-04 04:59:57.010
2017-03-04 17:39:50.460
2017-03-04 05:28:22.610
2017-03-04 20:54:39.257
2017-03-04 17:33:19.107
Try below query and also check your CreatedOn data type as DATETIME OR
VARCHAR
DECLARE #StartDate DATETIME,#EndDate DATETIME
SET #StartDate = '2017-03-04 00:50:00.000'
SET #EndDate = '2017-03-05 01:30:00.000
SELECT * FROM table (NOLOCK)
WHERE DATEDIFF(DAY,CreatedOn,#StartDate) <= 0 AND
DATEDIFF(DAY,CreatedOn,#EndDate) >= 0
As others said, there is no way you get different results for the given CreatedOn test data. You need to post actual results vs expected results if you still have problem.
Here is the script I tested and it always prints Yes (as the date is in range)
SET NOCOUNT ON
DECLARE #StartDate DATETIME = '2017-03-04 00:50:00.000',
#EndDate DATETIME = '2017-03-05 01:30:00.000'
DECLARE #CreatedOn TABLE
(
id INT IDENTITY,
CreatedOn DATETIME
)
INSERT #CreatedOn (CreatedOn)
VALUES ('2017-03-04 04:59:57.010'),
('2017-03-04 17:39:50.460'),
('2017-03-04 05:28:22.610'),
('2017-03-04 20:54:39.257'),
('2017-03-04 17:33:19.107'),
DECLARE #index INT = (SELECT COUNT(1) FROM #CreatedOn)
DECLARE #testDate DATETIME
WHILE #index >= 1
BEGIN
SELECT
#testDate = CreatedOn
FROM #CreatedOn
WHERE id = #index
IF #testDate BETWEEN #StartDate AND #EndDate
PRINT CAST(#testDate AS VARCHAR) + ' Yes'
ELSE
PRINT CAST(#testDate AS VARCHAR) + ' No'
SET #index = #index - 1
END
However the DateTime values are region dependent. If you are having the CreatedOn variable/field values in YYYYMMDD or YYYY-MM-DD format, they are language independent.
You might only get different results if you are using a different format. For example if you are trying to validate the date range for '04.03.2017 18:00', it will fail as it will be interpreted as March 4th 2017 in English regional settings.
Here is a small test script.
SET LANGUAGE 'German'
DECLARE #testDateRegion DATETIME = '04.03.2017 15:24'
PRINT CAST(#testDateRegion AS VARCHAR)
GO
SET LANGUAGE 'English'
DECLARE #testDateRegion DATETIME = '04.03.2017 15:24'
PRINT CAST(#testDateRegion AS VARCHAR)
and the output is,
Die Spracheneinstellung wurde auf Deutsch geändert.
Mär 4 2017 3:24PM
Changed language setting to us_english.
Apr 3 2017 3:24PM

convert string to both date and time

I have a data where date and time comes up in yyyymmdd_time (20161012_1528) format.
I want to convert it to date time in SQL Server DB as 2016-10-12 15:28:00:00
is there any straight forward way to do this.or have to create a custom function?
Declare #String varchar(25) = '20161012_1528'
Select cast(left(#String,8)+' '+Stuff(right(#String,4),3,0,':') as datetime)
Or
Select cast(Stuff(Replace(#String,'_',' '),12,0,':') as datetime)
Returns
2016-10-12 15:28:00.000
Please try following method,
It requires a few datetime and convertion functions to be used
declare #dt datetime
declare #str varchar(40) = '20161012_1528'
select #dt =
DATEADD(MI, CAST(right(#str,2) as int),
DATEADD(hh, cast(SUBSTRING(#str,10,2) as int),
CONVERT(datetime, left(#str,8))
)
)
select #dt
The closest I could find was datetime format 112 which does not account for the "_hhmm". I would highly recommend just placing the convert into your T-SQL as the optimizer does not handle UDFs very well.
The T-SQL looks like:
DECLARE #datetimestring nvarchar(max) = '20161012_1528'
SELECT
dateadd(
minute,convert(
int,substring(
#datetimestring,charindex(
'_',#datetimestring
)+3,2
)
),dateadd(
hour,convert(
int,substring(
#datetimestring,charindex(
'_',#datetimestring
)+1,2
)
),convert(
datetime, substring(
#datetimestring,0,charindex(
'_',#datetimestring
)
), 112
)
)
)
The other option is to format the string to the expected date format which is shorter.
SELECT
convert(
datetime,replace(
stuff(
stuff(
stuff(
#datetimestring,5,0,'-'
),8,0,'-'
),14,0,':'
),'_',' '
)
)

Convert varchar column to datetime in sql server

I have a table with following definition and data.
Definition:
CREATE TABLE [dbo].[TestTB]
(
[CREATEDATE] [nvarchar](50) NULL
) ON [PRIMARY]
Data:
10/9/2014
1/26/2015
2/16/2015
When I run the query:
Select
CAST(CREATEDATE AS DATETIME) as CREATEDATE
FROM
[dbo].[TestTB]
It is throwing error:
Msg 241, Level 16, State 1, Line 1
Conversion failed when converting date and/or time from character string.
The above does not work even after running
SET DATEFORMAT dmy
However the following query works fine
DECLARE #data nvarchar(50)
SET #data = ' 10/9/2014 '
Select CAST(#data as DateTime)
Above query returns: 2014-10-09 00:00:00.000
How do I convert a date string (of mm/dd/yyyy format) stored in a column to datetime?
First, if your table column is "DateTime" type than it will save data in this format "2014-10-09 00:00:00.000" no matter you convert it to date or not. But if not so and if you have SQL Server version 2008 or above than you can use this,
DECLARE #data nvarchar(50)
SET #data = '10/9/2014'
IF(ISDATE(#data)>0)
BEGIN
SELECT CONVERT(DATE, #data)
END
Otherwise
DECLARE #data nvarchar(50)
SET #data = '10/9/2014'
IF(ISDATE(#data)>0)
BEGIN
SELECT CONVERT(DATETIME, #data)
END
To Insert into table
INSERT INTO dbo.YourTable
SELECT CREATEDATE FROM
(
SELECT
(CASE WHEN (ISDATE(#data) > 0) THEN CONVERT(DATE, CREATEDATE)
ELSE CONVERT(DATE, '01/01/1900') END) as CREATEDATE
FROM
[dbo].[TestTB]
) AS Temp
WHERE
CREATEDATE <> CONVERT(DATE, '01/01/1900')
DECLARE #data nvarchar(50)
SET #data = ' 10/9/2014 '
SELECT CONVERT(datetime, #data, 101)
SELECT CONVERT(datetime, CREATEDATE, 101) as CREATEDATE
FROM [dbo].[TestTB]
http://www.sqlfiddle.com/#!6/f2103
please check this http://msdn.microsoft.com/en-us/library/aa226054%28SQL.80%29.aspx
Try this out:
SELECT IIF(ISDATE(CREATEDATE) = 1, CONVERT(DATETIME, CREATEDATE, 110), CREATEDATE) as DT_CreateDate
FROM [dbo].[TestTB]
SQL Fiddle Solution
nvarchar to datetime is an implicit conversion, it means you can do this:
declare #strDate nvarchar(50), #myDate datetime
set #strDate = '01/26/2013'
set #myDate = #strDate
But your problem is date format so you have to convert it, but you have to scpecify the format or style and the code of the style you're using is 101 (according to this table) so the secure way:
declare #strDate nvarchar(50), #myDate datetime
set #strDate = '01/26/2013'
set #myDate = CONVERT(DATETIME, #strDate, 101)
You can skip the code but with diferent configuration(server) that code will break.
If you use the ISO style (yyyymmdd) you never would'nt have to worry and the conversion would be implicit:
declare #strDate nvarchar(50), #myDate datetime
set #strDate = '20150421' --ISO style (yyyymmdd)
set #myDate = #strDate

Concat Date and Time of two DateTime values

I have two datetime values like A="2014-04-28 00:00:00.000" and B="2014-05-04 04:25:21.340".
And I am expecting the result "2014-04-28 04:25:21.340", that is,the value consisting of the date part from A and time part from B.
How can I do that?
Try this
SELECT A + CAST(B as TIME)
SQL FIDDLE DEMO
#m hasan's answer is correct. If you can't guarantee that the time portion of A will be zero:
(SQL Server 2008 onwards:)
declare #A datetime = '2014-04-28 00:00:00.000'
declare #B datetime = '2014-05-04 04:25:21.340'
select cast(cast(#a as date) as datetime) + cast(#b as time)
SQL Fiddle

Best way to compare dates without time in SQL Server

select * from sampleTable
where CONVERT(VARCHAR(20),DateCreated,101)
= CONVERT(VARCHAR(20),CAST('Feb 15 2012 7:00:00:000PM' AS DATETIME),101)
I want to compare date without time
Is above query is ok? or other better solution you suggest
I am using SQL Server 2005
Date saved in UTC format on server
Users against this data belongs different timezone
Simple Cast to Date will resolve the problem.
DECLARE #Date datetime = '04/01/2016 12:01:31'
DECLARE #Date2 datetime = '04/01/2016'
SELECT CAST(#Date as date)
SELECT CASE When (CAST(#Date as date) = CAST(#Date2 as date)) Then 1 Else 0 End
Don't use convert - that involves strings for no reason. A trick is that a datetime is actually a numeric, and the days is the integer part (time is the decimal fraction); hence the day is the FLOOR of the value: this is then just math, not strings - much faster
declare #when datetime = GETUTCDATE()
select #when -- date + time
declare #day datetime = CAST(FLOOR(CAST(#when as float)) as datetime)
select #day -- date only
In your case, no need to convert back to datetime; and using a range allows the most efficent comparisons (especially if indexed):
declare #when datetime = 'Feb 15 2012 7:00:00:000PM'
declare #min datetime = FLOOR(CAST(#when as float))
declare #max datetime = DATEADD(day, 1, #min)
select * from sampleTable where DateCreated >= #min and DateCreated < #max
SELECT .......
FROM ........
WHERE
CAST(#DATETIMEVALUE1 as DATE) = CAST(#DATETIMEVALUE2 as DATE)
The disadvantage is that you are casting the filter column.
If there is an index on the filter column, then, since you are casting, the SQL engine can no longer use indexes to filter the date more efficiently.
Description
Don't convert your Date to a varchar and compare because string comparisson is not fast.
It is much faster if you use >= and < to filter your DateCreated column.
If you have no parameter (like in your sample, a string) you should use the ISO Format <Year><Month><Day>.
Sample
According to your sample
DECLARE #startDate DateTime
DECLARE #endDate DateTime
SET #startDate = '20120215'
SET #endDate = DATEADD(d,1,#startDate)
SELECT * FROM sampleTable
WHERE DateCreated >= #startDate AND DateCreated < #endDate
More Information
MSDN - DATEADD (Transact-SQL)
Use 112 CONVERT's format
select *
from sampleTable
where
CONVERT(VARCHAR(20),DateCreated,112)
= CONVERT(VARCHAR(20),CAST('Feb 15 2012 7:00:00:000PM' AS DATETIME),112)
or
if your sql server version 2008+ use DATE type
select * from sampleTable
where CONVERT(DATE,DateCreated)
= CONVERT(DATE,CAST('Feb 15 2012 7:00:00:000PM' AS DATETIME))
declare #DateToday Date= '2019-10-1';
print #DateToday;
print Abs(datediff(day, #DateToday,CAST('oct 1 2019 7:00:00:000PM' AS DATETIME))) < 3
this is compare whin 3 days.
i test this on SQL Server 2014, it works.
select * from sampleTable
where date_created ='20120215'
This will also compare your column with the particular date
without taking time into account