Home > Mobile >  Conversion failing for date formatting
Conversion failing for date formatting

Time:12-07

I have an nvarchar(100) column which has a value ' 8/11/2022'.

I receive and error when trying to convert it to date...

select convert(date,[date],103)
from [Source].[TableName] s_p 
--Msg 241, Level 16, State 1, Line 96
--Conversion failed when converting date and/or time from character string.

I have tried a number of different ways to approach but I can't find one to give me '08/11/2022'

select Date = REPLACE(LEFT([Date],10),' ','0')
from [Source].[TableName] s_p 
--Outcome  8/11/2022

select REPLACE([DATE],' 8/','08/')
from [Source].[TableName] s_p 
--Outcome  8/11/2022

select convert(nvarchar,[date],103) 
from [Source].[TableName] s_p
--Outcome  8/11/2022

The strange thing is when I copy and paste from the results grid then do a replace it works fine...

select REPLACE(' 8/11/2022',' 8/','08/')
--Outcome 08/11/2022

Please help me to get to '08/11/2022' or any single digit to having a leading 0.

Thanks, Will

CodePudding user response:

Different languages and cultures have their own formatting preferences around date values. Some places like M/dd/yyyy. Some places like dd/MM/yyyy. Or perhaps d-M-YYYY (different separators and conventions around leading zeros). The point is it's not okay to go into a place and impose our own preferences and norms on that culture.

The SQL language is no different. It really is it's own language, and as such has it's own expectations around date handling. If you violate these expectations, you should not be surprised when there are misunderstandings as a result.


The first expectation is for date and datetime values to be stored in datetime columns. It's hard to understate how much of a difference this can make for performance and correctness.


But let's assume that's not an option, and you have no choice but to use a string column like varchar or nvarchar. In that situation, there is still an expectation around how date values should be formatted.

Any database will do better if you use a format which stores the date parts in order by descending length. For example, ISO-8601 yyyy-MM-ddTHH:mm:sss[.fff] This is important to allow greater than/less than comparisons to work, it can greatly help with indexes and performance, and it makes cast/convert operations to datetime values MUCH more likely to succeed and be accurate.

For SQL Server specifically, there are three acceptable formats:
yyyy-MM-ddTHH:mm:sss[.fff],
yyyyMMdd HH:mm:ss[.fff], and
yyyyMMdd.

Anything else WILL have date values that don't parse as expected. Any string manipulation done to call the CONVERT() method should focus on reaching one of these formats.

With that in mind, and assuming 8/11/2022 means November 8 and not August 11 (given the 103 convert format), you need something like this:

convert(datetime, 
  right([date], charindex('/', reverse([date]))-1) -- year
    right('0'   replace(substring([date], charindex('/', [date]) 1, 2), '/', ''), 2) -- month
    right('0'   left([date], charindex('/',[date])-1),2)  -- day
)

And you can see it work here:

https://dbfiddle.uk/lM8sVySh

Yes, that's a lot of code. It's also gonna be more than a little slow. And again, the reason why it's so slow and complicated is you jumped in with your own cultural expectations and failed to respect the language of the platform you're using.


Finally, I need to question the premise. As the fiddle above shows, SQL Server is perfectly happy to convert this specific value without error. This tells me you probably have more rows, and any error is in fact coming from a different row.

With that in mind, one thing to remember is a WHERE clause condition will not necessarily run or filter a table before a CONVERT() operation in the SELECT clause. That is, if you have many different kinds of value in this table, you cannot guarantee your CONVERT() expression will only run on the date values, no matter what kind of WHERE clause you have. Databases do not guarantee order of operations in this way.

The problem could also be some invisible unicode whitespace.

Another possibility is date formats. Most cultures that prefer a leading day, instead of month or year, tend to also strongly prefer to see the leading 0 in the first place. That the zero is missing here makes me wonder if you might have a number of dates in the column that were formatted by, say, Americans. So then you try to parse a column with values both like 02/13/2022 and 13/02/2022. Obviously those dates can't both use the same format, since there is no 13th month.

In that case, best of luck to you, because you no longer have any way to know for certain whether 2/3/2022 means March 2nd or February 3rd... and trying to guess (by say, assuming your own common format) is just exacerbating the same mistake that got you into this mess in the first place.

It's worth noting all three of these possibilities would be avoided had you used DateTime columns from the beginning.

CodePudding user response:

You'll want to use LPAD to add 0 to string, then CAST() string as date if you want to change to date data type

  • Related