I've dealt with MS SQL Server datetime types for a long time but never thought why the following is happening:
- I query a table that contains a smalldatetime column. This smalldatetime is always returned in the format
yyyy-MM-dd hh:mm:ss
- Now I write a different query on which I want to apply a smalldatetime filter in the WHERE clause, something like
WHERE TimeStamp >= 'yyyy-MM-dd hh:mm:ss'
- SQL Server retrieves an error and tells me that was not possible to convert that nvarchar to a valid smalldatetime
It appears that it only works if I change the specified format and I write it using the european format, like WHERE TimeStamp >= 'dd-MM-yyyy hh:mm:ss'
.
Why is SQL Server showing me the dates in a format that is not covertable or valid when applied back to itself?
I don't have any problem in changing the date format when writing queries, but I want to play with these dates at an application level (Java-JDBC app) and I don't want to be applying date format changes all the time...
Could anyone explain me why this is happening and if there is any way to solve it at a DB level?
Thanks!!
Edit: Please see the screenshot of the error in Management Studio below. enter image description here
2 Answers 2
The only truly safe formats for DATETIME/SMALLDATETIME in SQL Server are:
yyyyMMdd
yyyyMMdd hh:nn:ss[.mmm] -- or up to [.mmmmmmm] for datetime2 etc.
yyyy-MM-ddThh:nn:ss[.mmm] -- or up to [.mmmmmmm] for datetime2 etc.
----------^ yes, that T is important!
Anything else is subject to incorrect interpretation by SQL Server, Windows, the provider, the application code, end users, etc. For example, the following always breaks:*
SET LANGUAGE FRENCH;
SELECT CONVERT(DATETIME, '2013-11-13');
Result:
Le paramètre de langue est passé à Français.
Msg 242, Level 16, State 3, Line 2
La conversion d'un type de données varchar en type de données datetime a créé une valeur hors limites.
Just changing the language (which any of your user sessions can do) forced SQL Server to interpret that as YYYY-DD-MM
instead of YYYY-MM-DD
. Similar things can happen with setting like DATEFORMAT
. But these settings are literally ignored when using the above two formats.
Always, always, always use one of the above two formats. If you are passing a variable as a string, stop doing that. If you can't, check to make sure it passes ISDATE()
first. If you are letting people type any date string into a form field, stop doing that, too. Use a date-picker or calendar control and dictate the format of the string before you pass it to SQL Server. Well, depending on the language, just keep it as a datetime value and don't convert it to a string at all.
Please read this post:
There is an exception: SELECT CONVERT(DATE, 'yyyy-mm-dd');
will not break. But I err on the side of consistency rather than using a format only in the one place where I know it doesn't break, and having to use a safer format everywhere else.
-
Comments are not for extended discussion; this conversation has been moved to chat.2017年08月29日 07:35:51 +00:00Commented Aug 29, 2017 at 7:35
According to SQL Server Books Online Write International Transact-SQL Statements you could wrap your date strings like so:
{ ts 'yyyy-mm-dd hh:mm:ss[.fff] '}
Example:
{ ts '1998-09-24 10:02:20' }
This might be easier to accomplish for you because instead of inserting a T
in the middle, you are just concatenating strings at the beginning and the end.
One caveat: you have no control over the precise type when using this syntax; the result is always datetime. To achieve a smalldatetime result (as in the question), you would need to use a convert (or cast). In which case, you might as well use just convert (with the correct style parameter) in the first place.