SQL Server expecting different date format - sql-server

I have set the SQL Server's default language to "British". The following correctly returns 23...
sp_configure 'default language'
I have also set the language of my login to "British" too with...
sp_defaultlanguage #loginame = 'Login123', #language = 'British'
However, when I attempt to specify 13/12/2015 as a DateTime stored procedure parameter from ASP Classic, I get...
Error converting data type nvarchar to datetime.
From Management Studio, with the correct login, it works.
Why would ASP Classic have this effect? I'm pretty sure it's using the correct connection string.
EDIT:
Its not the connection string. Somehow the date's format is being converted incorrectly before being sent to the database. I can see this from Profiler.

Use CONVERT with style:
British/French
103 = dd/mm/yyyy
SELECT CONVERT(DATETIME, '13/12/2015', 103);
-- with stored procedure
DECLARE #d DATETIME = CONVERT(DATETIME, '13/12/2015', 103);
EXEC [dbo].[my_stored_procedure] #d;
Another method is to use ISO 8601 date literal which is culture independent:
The advantage in using the ISO 8601 format is that it is an international standard. Also, datetime values that are specified by using this format are unambiguous. Also, this format is not affected by the SET DATEFORMAT or SET LANGUAGE settings.
yyyy-mm-ddThh:mm:ss[.mmm]
EXEC [dbo].[my_stored_procedure] '2015-12-13T00:00:00'

Related

How to specify date format used by ADO.NET when passing it to a stored procedure? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I am using ADO.NET to pass a datetime parameter to a stored procedure and I am getting
Error converting data type varchar to datetime
on servers configured with DATEFORMAT ydm.
I have a simple stored procedure (it just takes a parameter and do nothing):
CREATE PROCEDURE [dbo].[TestDate]
#date AS datetime
AS
BEGIN
RETURN 0
END
I am executing it with ADO.NET by using datetime parameter:
Dim param As SqlParameter = New SqlParameter()
param.SqlDbType = SqlDbType.DateTime
param.Value = New Date(2021, 1, 13)
Execution on the SQL side looks like this:
EXEC sp_executesql N'EXEC dbo.TestDate #date = #date', N'#date datetime', #date = '2021-01-13 00:00:00.000'
and it works on most of our servers. Unfortunately one of our clients has different configuration. I have simulated this by adding SET DATEFORMAT ymd to previous execution, so when it runs it throws
Error converting data type varchar to datetime
SET DATEFORMAT ydm;
EXEC sp_executesql N'EXEC dbo.TestDate #date = #date', N'#date datetime', #date = '2021-01-13 00:00:00.000'
It seems like ADO.NET passes dates in a ODBC format which is sensitive to dateformat / language setting. Do you have some idea how to overcome this issue? (I have tried passing dates as strings in ISO 8601 format and it works with this example, but some of our other queries have other issues with that and I don't like this kind of "dirty tricks").
Edit:
Thanks for replies, I have checked sp code once more. I have further simplified the example: I have captured execution of real procedure with profiler on the client server and I have deleted all "noise code". On client environment (from application and Management Studio) I am getting
Error converting data type varchar to datetime
(which can be simulated by setting dateformat: SET DATEFORMAT dmy - I have checked it from DBCC USEROPTIONS):
exec sp_executesql N'',N'#date datetime',#date='2021-01-27 10:04:55.263'
Dates have no format, they're binary values. In .NET DateTime uses a tick count field internally. SQL Server uses several date types, none of which is based, parsed or stored as a string. ADO.NET passes parameters as separate, binary parameters to the RPC call to the server.
One way or the other the data access code that's missing is converting dates to strings instead of using parameterized queries.
This code wouldn't convert dates to strings or need parsing on the server:
Using con As SqlConnection = New SqlConnection(connectionString)
Using cmd As New SqlCommand("TestDate", con)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.Add("#date", SqlDbType.Date).Value = New Date(2021, 1, 13)
cmd.ExecuteNonQuery()
The type could be any of the date types, eg: SqlDbType.DateTime, SqlDbType.DateTime2 or SqlDbType.DateTimeOffset. The type that best matches the stored procedure parameter is Date
What about SSMS ?
In SSMS the queries are written as text. Even a parameter declaration in the end uses text. You need to provide the correct date literal to avoid localization issues.
datetime is a legacy type that's affected by DATEFORMAT unless a full ISO8601 string or an unseparated YYYYMMDD string is used. This means that YYYY-MM-DD can be parsed as YYYY-DD-MM if datetime is used.
The newer types don't have this problem. date, the correct type for this parameter and datetime2, datetimeoffset all recognize YYYY-MM-DD no matter what DATEFORMAT is.

Default Date Formatting in SQL Server 2017

I am currently debugging a scenario in which dates need to be read from a string in a stored procedure.
The code that we have used is a simple convert statement.
e.g.
SELECT CONVERT(DATETIME, #dateInput)
The problem comes when I need to test the dates coming from the Chinese date format (yyyy.mm.dd) which is ISO 102.
What settings in Windows 10 / SQL Server must be set so that running SELECT CONVERT(DATETIME, '2020.05.16') will not return
"The conversion of a varchar data type to a datetime data type resulted in an out-of-range value."
I understand that using SELECT CONVERT(DATETIME, '2020.05.16', 102) would work but that would make the universal stored procedure incorrect when running with different windows date formats
Along with changing my windows settings to reflect the same date format I also changed:
My default language of my SQLEXPRESS server in Properties > Advanced > Default Language
My default language of my SQL User Login Properties > General > Default Language
This meant that it could read the direct string value without needed the ISO 102 identifier.
If the input value is always in the format yyyy.MM.dd then use the appropriate style code (don't rely on the language setting of the LOGIN):
DECLARE #StringInput varchar(10) = '2020.05.16';
SELECT CONVERT(datetime,#StringInput,102);
Ideally, however, instead of defining your parameter as a varchar define it as a datetime in the first place and have the application pass the correct data type; not a string. But that is a different question for the language your application is written in.

SQL Server stored procedure: datetime parameter is wrong format sometimes depending on dateformat of country

This SQL Server stored procedure takes several parameters, and one of them is a datetime data type.
We've just began to localize the application in Europe, and the problem is that they're receiving this:
Error converting data type nvarchar to datetime.
I've done my reading on datetime, so I believe what is happening is the application is posting the date as dd/mm/yyyy to SQL Server, but since the database has a default language of English and expects mm/dd/yyyy, there is an error.
Sample input that produces error:
#LastUpdatedDate = N'21.01.2016 03:54:08'
My coworker in Europe said that when he set the default language of the database to German, the error quit occurring.
This error has not shown up in the USA/Canada, and I'm assuming that if the application AND SQL Server are running the same default datetime format, then no issues. However, we (here in USA), need to work with their application and database in Europe, so now we get the error.
Here's the stored procedure:
CREATE PROCEDURE [dbo].[addUser]
(
#UserID NVARCHAR ( 50 ),
#AccountID NVARCHAR( 50 ) = '00000000000000000000000000000000',
#Password NVARCHAR( 50 ),
#FirstName nvarchar(50),
#LastName nvarchar(50),
#Telephone nvarchar(25),
#Mobile nvarchar(25),
#FAX nvarchar(25),
#EmailAddress nvarchar(50),
#CurrentUserID nvarchar(50),
#LastUpdatedBy nvarchar(50),
#LastUpdatedDate datetime
)
AS
BEGIN TRANSACTION
INSERT INTO tbUsers (UserID, AccountID, Password, Status, VPID, EvalStatusID, FirstName, LastName, Telephone, Mobile, FAX, EmailAddress, LastUpdatedBy, LastUpdatedDate)
VALUES (#UserID, #AccountID, #Password, 'A', 'PM', 'ACTIVE', #FirstName, #LastName, #Telephone, #Mobile, #FAX, #EmailAddress, #LastUpdatedBy, #LastUpdatedDate)
I don't have access to the application code yet, but question is:
Is there a way to catch the error and fix the datetime input value depending on how database is configured?
I tried using SET DATEFORMAT dmy before the BEGIN TRANSACTION, but it errors out before that.
Yes, we could probably alter the application code to use a language-neutral datetime format, but that may not be feasible.
There are many formats supported by SQL Server - see the MSDN Books Online on CAST and CONVERT. Most of those formats are dependent on what settings you have - therefore, these settings might work some times - and sometimes not.
The way to solve this is to use the (slightly adapted) ISO-8601 date format that is supported by SQL Server - this format works always - regardless of your SQL Server language and dateformat settings.
The ISO-8601 format is supported by SQL Server comes in two flavors:
YYYYMMDD for just dates (no time portion); note here: no dashes!, that's very important! YYYY-MM-DD is NOT independent of the dateformat settings in your SQL Server and will NOT work in all situations!
or:
YYYY-MM-DDTHH:MM:SS for dates and times - note here: this format has dashes (but they can be omitted), and a fixed T as delimiter between the date and time portion of your DATETIME.
This is valid for SQL Server 2000 and newer.
If you use SQL Server 2008 or newer and the DATE datatype (only DATE - not DATETIME!), then you can indeed also use the YYYY-MM-DD format and that will work, too, with any settings in your SQL Server.
Don't ask me why this whole topic is so tricky and somewhat confusing - that's just the way it is. But with the YYYYMMDD format, you should be fine for any version of SQL Server and for any language and dateformat setting in your SQL Server.
The recommendation for SQL Server 2008 and newer is to use DATE if you only need the date portion, and DATETIME2(n) when you need both date and time. You should try to start phasing out the DATETIME datatype if ever possible
Update: if you're on SQL Server 2012 or newer, you could use the new TRY_PARSE function in T-SQL which allows you to parse strings representing dates safely. You can specify a locale to use, and if the parse doesn't work, you get back a NULL instead of an exception.
Try this:
DECLARE #input NVARCHAR(100) = N'21.01.2016 03:54:08'
SELECT
TRY_PARSE(#input AS DATE USING 'en-gb')
Should return a valid DATE value of Jan-21, 2016 - no matter what language/locale your SQL Server is set to

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