Sql Server strict convert from varchar to datetime - sql-server

I'm converting varchar to datetime in Sql Server 2005. Can I force Sql Server to fail if provided varchar has unexpected format?
Example:
select convert(datetime, '01-2010-02', 103)
Expected result: query fails because 103 means dd/mm/yyyy (see msdn).
Actual result: 2010-02-01 00:00:00.000
Main purpose of requested enforcement is order of day and month. If varchar is provided in format yyyy-mm-dd then Sql Server will treat mm as day and dd as month because of day/month order in provided format (dd/mm/yyyy).
Note: I can write custom function to manually handle this case. But I hope such enterprise DB already can work strictly with data.

I am afraid you have to use CLR Function and take advantage of using DateTime.TryParseExact method. Not an elegant solution but could work.

You can compare the date with a convert to datetime and back again. I don't know for sure if there are any pitfalls doing like this but my limited tests has not discovered any.
if #StrDate = convert(varchar(10), convert(datetime, #StrDate, 103) ,103)

Whenever SQL Server sees a clear candidate for Year, it will always be used as Year.
The remaining DM parts are determined from the order within the DMY setting or the convert format. If that weren't true, then very simple conversions will fall apart.
Example
set dateformat dmy
select 1 a,CONVERT(datetime, '1-2-3') b
union all
select 2,CONVERT(datetime, '2001-2-3')
union all
select 3,CONVERT(datetime, '2001-3-2')
Output
a b
----------- -----------------------
1 2003-02-01 00:00:00.000
2 2001-03-02 00:00:00.000
3 2001-02-03 00:00:00.000
The 2nd and 3rd explicitly put the Year in front, and that is ok
EDIT
Books Online has this to say http://msdn.microsoft.com/en-us/library/ms180878.aspx#StringLiteralDateandTimeFormats
There are quite a few exceptions to SET DATEFORMAT, which plays a role regardless of the 3rd param to CONVERT.
The SET DATEFORMAT session setting does not apply to all-numeric date entries
This [ISO 8601] format is not affected by the SET DATEFORMAT, SET LANGUAGE, of login default language settings.
The SET DATEFORMAT session setting is not applied when you specify the month in alphabetical form.
etc
To specifically validate dd/mm/yyyy, use the below instead
set dateformat dmy
declare #input varchar(10) set #input = '12-2010-01'
-- convert allows the date through
select convert(datetime, #input, 103) -- 2010-01-12 00:00:00.000
-- the case below returns 0 { = invalid date }
-- this uses 8-digit format which is always interpreted YYYYMMDD regardless
-- of language or dateformat settings
select case
when #input not like '__/__/____' then 0
else isdate(right(#input,4)+right(left(#input,5),2)+left(#input,2))
end

Related

SQL Server issues when getting records starting from a date onwards

I want to obtain all records starting from a date (included) onwards.
I get different records if I use below in where clause:
SELECT * FROM MyTable WHERE DateTimeField >= '20101201'
than if I use below:
SELECT * FROM MyTable WHERE DateTimeField >= Convert(datetime, '2010-12-01')
Why don't I get the same number of registers?
I use SQL Server 2008.
Your literal constant in the second case is language dependent, here is an example:
set language [British English]
SELECT Convert(datetime, '2010-12-01');
----
-- 2010-01-12 00:00:00.000
set language us_english
SELECT Convert(datetime, '2010-12-01');
----
-- 2010-12-01 00:00:00.000
While '20121201' is language independent.
So I suppose your session language (defined by your login language unless changed explicitely) is different from us_english and to fix the issue you should use language independent date literals 'yyyymmdd'

Why does SQL server's Date format affect date conversions with Timestamps

I'm trying to convert a varchar containing a date into a datetime field in SQL server using the following script
SELECT cast('2017-12-14 14:30:41.007' as datetime)
When I ran this on my local Machine that uses DateFormat myd this worked fine and returned a valid datetime.
When I ran this statement on my server that uses Dateformat dym the server returned the following error
The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.
Why is '2017-12-14 14:30:41.007' a valid datetime under "myd" but not under "dym" even though it's neither a "dym" nor a "myd" date?
I have found a work around for the issue btw, I'm asking because i want to understand what is going on in SQL server
It is because SQL server is interpreting 14 as a month number and there are only 12 months. If you change the 14 to 11 and run this script you will see the difference:
SET DATEFORMAT myd
SELECT DATEPART(month,cast('2017-12-11 14:30:41.007' as datetime))
SET DATEFORMAT dym
SELECT DATEPART(month,cast('2017-12-11 14:30:41.007' as datetime))
/*
Output:
12
11
*/
To make things consistent for all time formats put a T in the middle of the date and time. This makes SQL server think the date is in ISO8601 format.
SET DATEFORMAT myd
SELECT DATEPART(month,cast('2017-12-11T14:30:41.007' as datetime))
SET DATEFORMAT dym
SELECT DATEPART(month,cast('2017-12-11T14:30:41.007' as datetime))
/*
Output:
12
12
*/
'2017-12-14 14:30:41.007' seems to follow ODBC canonical with milliseconds default standard for time, date, datetime2, and datetimeoffset. If you are using MS SQL you can use CONVERT to cope with the specific style of the string parameter:
SELECT convert(datetime,'2017-12-14 14:30:41.007' , 121 )

Which settings provide SQL Server default datetime format?

Say, I have a table like this :
Table name "DateTimeFormatCheck" >
I used below query to insert :
Insert into [dbo].[DateTimeFormatCheck] ([DateTimeCheck]) values('11/19/2014 1:29 PM')
It inserted date like 2014-11-19 13:29:00.000 , but my insertion format(M/d/yyyy h:m tt) is not same as inserted date.
Now i want to know How SQL Server detect my string date format that i have provided ? and Why it always provide this format yyyy-MM-dd HH:mm:ss after insertion?
Thanks
Don't do that! Don't use strings instead of dates and don't use a culture-specific date or datetime format, it's a recipe for disaster.
SQL Server doesn't have a "date format", just formats it uses to convert dates to and from strings. One of them is the default, controlled by the server's collation. You can neither assume nor should you depend on a specific collation, so you should avoid conversions whenever possible. Moreover, passing a string value can prevent SQL Server from using indexes on date columns because it would have to convert the string to the underlying column type.
It's far easier and safer to pass dates as date-typed variables or parameters. You avoid the entire conversion mess this way, to and from and avoid SQL injection attacks.
There's no reason to pass strings instead of dates to the server. All SQL Server clients (including ADO.NET) allow you to execute parameterized queries. ORMs like NHibernate and Entity Framework also generate parameterized queries for date-typed columns.
Whenever you need to create a string literal, use one of the invariant formats like 20140913 or 2012-11-07T18:26:20
You can read more about it at Writing International T-SQL Statements
The format of sqlserver is yyyy-mm-dd, but you can define your input by execute the command
set dateformat dmy -- to accept dmy format
set dateformat mdy
select cast( '11-9-2014' as date)
set dateformat dmy
select cast( '11-9-2014' as date)
updated
Ideally you can not try to change format, you can validate your data and then insert.
Whenever we insert into datetime datatype, sqlserver will implicitly try to convert into mmddyyy hhmmss format. so if you given date as 19/11/2014 , it convert into 11/19/2014 means 19th nov 2014.
But if you give more than 12 in the middle portion, it will not convert implicitly and throw the error of conversion.
Other than mmddyyyy format, you must use to cast or convert function explicitly to allow the data insert or update.
Before the casting you can use ISDATE or TRY_PRASE or PARSE function in sqlserver, will check to conversion possible or not.
you can create a function or just add line as
declare #dt varchar(50) = '19-11-2014 10:10:41'
declare #dTable table ( datecolumn datetime)
INSERT into #dTable values (
case
when isdate(CONVERT( varchar(50), #dt)) = 1 then CONVERT( varchar(50), #dt) --'19-11-2014 10:10:41'
when isdate(CONVERT( varchar(50), #dt, 103) ) = 1 then CONVERT( datetime, #dt , 103 ) --'19-11-2014 10:10:41'
when isdate(CONVERT( varchar(50), #dt, 102) ) = 1 then CONVERT( datetime, #dt , 102 ) --'19-11-2014 10:10:41'
--when --give other format as above given and if not set in any dateformat , then simply return null
else
null
end )
select * from #dTable

Why if I set "default language" in spanish the GETDATE() still formating the date in english?

why if I do this on my SQL-Server 2008:
EXEC sp_configure 'default language', 5
reconfigure
Where the date format is dd/mm/yyyy:
select * from sys.syslanguages where langid = 5
returns
dateformat
----------
dmy
So if I do
select GETDATE()
I'm waiting for something like:
(no column name)
----------------
31/08/2013 13:20:44.590
but I get:
(no column name)
----------------
2013-08-31 13:20:44.590
I'm using SQL-Server 2008 Express compatibility mode 100
ADDED:
My real problem is that I need to pass to Stored Procedures dates in dd/mm/yyyy hh:mm to DATETIME variables, but the parser is still waiting for yyyy-mm-dd although I change the default language.
Thank you
The following is going to be rendered by Management Studio, irrespective of server settings:
SELECT GETDATE();
This is returning a datetime value to the client application, NOT A STRING. If you want a string, you can explicitly convert to a specific style:
As for the input to your stored procedures, please, please, please pass proper datetime parameters and not strings. There is no reason to allow users to enter freetext like 6/9/2013 when you really don't know if they meant September 6th or June 9th. The safe formats to pass to SQL Server are:
YYYYMMDD HH:MM:SS.nnn
YYYY-MM-DDTHH:MM:SS.nnn
Anything else can be misinterpreted. Which is why you shouldn't handle these as strings anywhere except at the final step of presentation / display.
you can use like this
Select CONVERT(varchar(100), GETDATE(),103)+' '
+CONVERT(varchar(100), GETDATE(),108) as now
the result is

Correct way of specifying a given date in T-SQL

I am writing some T-SQL which needs to enforce a minimum date value onto some null fields:
DECLARE #epoch DATETIME;
set #epoch='1900-01-01';
select min = ISNULL(ValidFromDate,#epoch)
Is the string '1900-01-01' always going to return a datetime of Jan 1 1900 in any environment or will SQL server try to parse the string according to local culture rules?
If that's not good enough, what is the recommended way of specifying a particular date/time in T-SQL?
The best format for string-based dates is the ISO-8601 standard format.
For DATETIME variables and columns, this is either YYYYMMDD (for dates without time; without any dashes!) or YYYY-MM-DDTHH:MM:SS (date + time).
Contrary to popular belief, YYYY-MM-DD for DATETIME variables is NOT language-/dateformat-independent! If you try this, the second CAST will result in an error:
SET LANGUAGE us_english
SELECT CAST('2011-07-20' AS DATETIME)
SET LANGUAGE british
SELECT CAST('2011-07-20' AS DATETIME)
but this will work:
SET LANGUAGE british
SELECT CAST('20110720' AS DATETIME)
This is the best format since it's indepdendent of your language and dateformat settings in SQL Server.
For SQL Server 2008 and columns of type DATE (just date - no time), the format can also be YYYY-MM-DD (with the dashes) and that works for all settings, too.
Why there is such a difference between DATE and DATETIME is beyond me - that's just the way it is for now!
See Tibor Karaszi's excellent The Ultimate Guide to the DateTime data types for even more details and examples.

Resources