Why does SQL Server convert VARCHAR to DATETIME using an invalid style? - sql

I can't make out from the documentation why SQL Server parses a text in a format other than the specified style.
Regardless of whether I provide text in the expected format:
SELECT CONVERT(DATETIME, N'20150601', 112)
or incorrect format (for style 113):
SELECT CONVERT(DATETIME, N'20150601', 113)
The results are the same: 2015-06-01 00:00:00.000 I would expect the latter to fail to convert the date (correctly).
What rules does it employ when trying to convert a VARCHAR to DATETIME? I.e. why does the latter (incorrect format style) still correctly parse the date?
EDIT: It seems I've not been clear enough. Style 113 should expect dd mon yyyy hh:mi:ss:mmm(24h) but it happily converts values in the format yyyymmdd for some reason.

Because the date is in a canonical format ie(20150101). The database engine falls over it implicitly. This is a compatibility feature.
If you swapped these around to UK or US date formats, you would receive conversion errors, because they cannot be implicitly converted.
EDIT: You could actually tell it to convert it to a pig, and it would still implicitly convert it to date time:
select convert(datetime,'20150425',99999999)
select convert(datetime,'20150425',100)
select convert(datetime,'20150425',113)
select convert(datetime,'20150425',010)
select convert(datetime,'20150425',8008135)
select convert(datetime,'20150425',000)
And proof of concept that this is a compatibility feature:
select convert(datetime2,'20150425',99999999)
Although you can still implicitly convert datetime2 objects, but the style must be in the scope of the conversion chart.

Reason why is the date N'20150601' converted to valid datetime is because of fact that literal N'20150601' is universal notation of datetime in SQL Server. That means, if you state datetime value in format N'yyyymmdd', SQL Server know that it is universal datetime format and know how to read it, in which order.

You should convert to varchar type in order to apply those formats:
SELECT CONVERT(varchar(100), CAST('20150601' as date), 113)
OK, you are converting datetime to datetime. What did you expect? In order to apply formats you should convert to varchar and you have to have date or time type as second parameter.

Related

SQL Server nvarchar to date

I'm trying to write a query and convert a nvarchar to a date. I've tried the below but keep receiving an error:
Conversion failed when converting date and/or time from character string.
cast(columnName as DATE) as castDate
convert(Date, columnName, 23) as convertDate
(nvarchar(max),null)
2021-12-30 02:22:24 UTC
Desired output:
2021-12-30
Date and time data types don't support 3 letter abbreviations for timezones (such as 'UTC' here). As you only need to date, then I would suggest you simply take the 10 left most characters and then CONVERT/CAST the value. I use TRY_CONVERT here, as due to the decision to use nvarchar for the data type (not even touching on the fact that it's MAX in length) you could have bad dates:
TRY_CONVERT(date,LEFT(YourColumn,10))
Fortunately, yyyy-MM-dd is an unambiguous format for the date data type.
I do, however, strongly suggest you fix your design. nvarchar is not an appropriate data type for a date and time value, and certainly a MAX length value (suggesting that the value of the date is likely to be more than 4,000 characters in length) is completely wrong. Most likely you should be using a datetimeoffset here (or maybe just as datetime2 if all your values are UTC).

Why procedure throws error if I pass it date i.e. 20/04/2020?

I am using this
CAST(NotifDate as date) between #FromNotifDate AND #ToNotifDate
but NotifDate is saved as varchar in table but FromNotifDate AND ToNotifDate are of Date type.
When I pass these parameters 08/06/2014 and 20/04/2020 09:40:17 it doesn't work and throws error i.e.
Conversion failed when converting date and/or time from character string.
but if I pass 08/06/2014 and 10/04/2020 09:40:17 it works.
Your current database locale settings are probably set to en-US or another where the date format is MM/dd/yyyy.
That makes 08/06/2014 and 10/04/2014 valid dates (but they are 6th of August and 4th of October, not 8th of June and 10th of April!), but not 20/04/2020.
To use a different date format, you can use CONVERT, with the proper style code (I believe it's 103 for dd/MM/yyyy (see documentation)
So, this should work for you : CONVERT(date, NotifDate, 103)
Note that, as a general recommendation, it would be beneficial that you input NotifDate as a proper SQL Date in your DB in the first place, if possible, to avoid having to do conversion like this in your queries.
Also, there the unambiguous and international standard ISO-8601 format yyyy-MM-dd which should be always parsed correctly by CAST, I recommend using it over any localized format where you can in your code infrastructure.
System having default date format is "MM/dd/yyyy" so while you set "10/04/2020 09:40:17" value so system throm an Error- out of range Error,
-- The conversion of a varchar data type
-- to a datetime data type resulted in an out-of-range value.
select cast('20/04/2020 09:40:17' as datetime)
-- get the current session date_format
select date_format
from sys.dm_exec_sessions
where session_id = ##spid
-- set the dateformat for the current session
set dateformat dmy
-- this should work
select cast('20/04/2020 09:40:17' as datetime)

Can't convert YYYYMMDD to date

I'm trying to view software that has been installed within the last 30 days. The format of my date is 20150327. When I try to the following condition in the where clause
and DateDiff(day,arp.InstallDate0,GetDate()) < 30
I receive the following error message:
Conversion failed when converting date and/or time from character
string.
I have also tried the following and was unsuccessful:
CONVERT(varchar(8),arp.InstallDate0,112)
As well as:
ISDATE(CONVERT(datetime,arp.InstallDate0,112))
When I add ISDATE, it finally runs the query, but it is not showing any data and I know that there are installs within the last 30 days, so I'm thinking the date is still not being recognized.
EDIT The InstallDate0 column is nvarchar.
You do not need a conversion format for YYYYMMDD when converting to date, datetime2, and datetimeoffset. SQL Server recognizes this ISO standard format with no conversion in these cases, regardless of internationalization settings (there is one setting that affects my preferred format of YYYY-MM-DD; the documentation is here). So, you could do:
where cast(arp.InstallDate0 as date) > dateadd(day, -30, getdate())
At this point: "Shame on you for storing dates as strings."
That said, it is better (in your case) to do the comparison as strings rather than dates. You have a good date format for this, so:
where arp.InstallDate0 > convert(varchar(8), dateadd(day, -30, getdate()), 112)
Why is this better? With no functions on the column name, the query can take advantage of an appropriate index (if one is available).
You must use the syntax below, as the first argument for the CONVERT function is the target data type
CONVERT(datetime,'20150327',112)
You must use the syntax below:
WHERE
DATEDIFF(day, CONVERT(datetime, arp.InstallDate0, 112), GetDate()) < 30
Try converting the format using a converter to convert it to a date/or time string through conversion of its characters, then using the string to convert the numbers into a more usuable format with additional conversion
CONVERT(datetime,'20150327',112)

SQL date formats

How can I convert this 201402110544 to date(2014-02-11) in SQL server 2008?
You can cast as DATE data type (https://msdn.microsoft.com/en-us/library/bb630352(v=sql.100).aspx)
SELECT CAST(datetime_value AS DATE)
SELECT CAST(GETDATE() AS DATE) --> 2015-08-18
If you have a string to cast as DATE you can use:
SELECT CAST(LEFT('201402110544', 8) AS DATE)
You trim out the time part, by taking 1st 8 chars (YYYYMMDD) and will result a valid string to cast as DATE.
If this format is always the same, you can do this
DECLARE #d VARCHAR(20)='201402110544'
SELECT CAST(SUBSTRING(#d,0,9) as DATETIME)
Also have a look at The ultimate guide to the datetime datatypes which explains in detail about handling date-times
String to date conversion sure is a weakness of SQL Server. CONVERT does that, but can only deal with a number of given formats. So you must convert your string into such a format first and then convert it to date afterwards.
One such format is 120 = 'yyyy-mm-dd hh:mi:ss' which I think comes closest to yours. Another 102 = 'yyyy.mm.dd' suffices to get the date.
convert(
date,
concat(substring(datestring, 1,4), '.',
substring(datestring, 5,2), '.',
substring(datestring, 7,2)),
102)
from data;
SQL fiddle: http://www.sqlfiddle.com/#!3/9eecb7/3689
EDIT: I stand corrected. Horia is right; CAST supports 'yyyymmdd', so you can use it directly by merely cutting of the string's time part. This is more readable than my suggestion above, which makes CAST the better option in your case.

Store DateTime as culture independent in SQL Server 2008

I currently have a challenge of storing a DateTime value in a NVarChar field so that it's culture independent.
I've read that you can convert the value to an int by using CONVERT(int, GETDATE(), 112) which should make it culture independent but the former statement doesn't store the time.
What is the industry standard of storing a DateTime as culture independent?
EDIT
Please note that I can't use DateTime in my scenario. It must be NVarChar.
EDIT 2
Alright, found the answer to my own question.
To convert a DateTime to it's binary(8) raw format:
convert(binary(8), GETDATE())
I then store the value in a VARCHAR field as follows:
CONVERT(VARCHAR(MAX), convert(binary(8), GETDATE()), 2)
To retrieve it back from the varchar field and convert it to DateTime:
CONVERT(DateTime,CONVERT(binary(8), [TextField], 2))
As var as I'm concerned, this will store a DateTime as culture independent.
EDIT 3
It seems like user Kaf has the best solution. I will rather use format 126 to convert it to text and then back to DateTime from text.
Thanks everyone and sorry for the confusion.
If you CANNOT store date as Datetime, you can use style 126 which gives ISO8601 format (yyyy-mm-ddThh:mi:ss.mmm (no spaces)). I think it is culture independent.
Fiddle demo
select convert(nvarchar(50),getdate(),126)
Best thing is to store Date as a DateTime/Date type.
You should use DATETIME or DATETIME2 data type to store date and time values. They are stored in binary format in the database and are culture independent.
You can read more on MSDN here: http://msdn.microsoft.com/en-us/library/ms187819(v=sql.100).aspx
More on how SQL Server stores the datetime values: "It uses 8 bytes to store a datetime value—the first 4 for the date and the second 4 for the time." (from: http://sqlmag.com/sql-server/solving-datetime-mystery)
I do not get this idea to store a date in a varchar field so that it is 'culture independant'. dateTime data type is culture independant. What is culture dependent is the way date values are displayed:
MM/dd/YYYY
dd/MM/YYYY
YYYY-MM-DD
etc
But, if the display changes, the underlying value itself is still the same ... and this is why you can easily 'convert' dates from one format to another....
So, for the sake of simplicity, I do strongly advise you to switch to a culture-independant, datetime field. Otherwise any further use of this field's content (calculation, display, print out, etc) will be a real PITA ...