Skip to content

shannonlowder.com

Menu
  • About
  • Biml Interrogator Demo
  • Latest Posts
Menu

Converting VARCHAR to DATETIME

Posted on March 28, 2010February 9, 2011 by slowder

Recently a post was made on LinkedIn asking how one would convert a date stored in a VARCHAR field could be converted to a DATETIME so date math could be performed.  Unfortunately, this problem is more common than it should be.  If users are given a free-form field to enter data, they’ll often enter unreliable data.  This is never intentional on the users’ part, it’s just a matter of course.

Examples
22/10/2010
1/2/3
asdf

These are just a few of the problem cases you can face when trying to convert free form dates into DATETIME.  Let’s consider each of these problems one at a time.

Non-numeric data

If the form were completely open, and they could type anything in, you will see some entries like our “asdf” example.  You may have seen the LIKE comparator used in a previous post.  If so, then the following code may look familiar.  @varcharDateField is just one value from our examples table.

IF PATINDEX('%[^0-9]\/%', @varcharDateField) > 0
BEGIN
 SELECT 'Non-numeric data found.'
END

What this will do is look for the position of the first character that is not 0 through 9, or a forward slash, or a backslash.  If it finds any other character, then it will trigger the part in the BEGIN .. END segment.  If we hit this point, we need to decide how to handle it.   This leads us into the next problem case.

Empty String or NULL

Just like the case where the user gave us a non-numeric value, we need to handle the case where no data was provided.  This is where I usually will ask the business users to provide me a “default” case.  In this situation, I’m going to say the business requirements will allow us to leave NULL as the default case.  If the field is non-numeric or blank, we will default to NULL instead.  But how can you detect a blank string?  I usually check the length of the string to determine if the string is blank.

IF LEN(@varcharDateField) < 1
BEGIN
   SELECT 'Blank string found.'
END

MM/DD/YYYY or DD/MM/YYYY?

The next cases we need to deal with are date format issues.  Did the user mean month then day, or day then month.  In the case of 3/10/1977 or 10/3/1977 both are valid.  But if I were entering my birthdate, only one is valid.  This is a case where you can’t really detect which case is right and wrong.

As a database programmer, you would inform the interface programmer, to put a note next to the field to choose one or the other as default.  Either month then day, or day then month.  Once you and the interface programmer come to a choice, you can then detect for error cases.  For the following detection, we’re going to say the assumption is MM/DD/YYYY.

Given months can only be 01-12, we can make sure the first two digits are in that range.  There are several ways to do that, but let’s take one of the easiest.

IF LEFT(@varcharDateField, 2) > 12
BEGIN
 SELECT 'String could be DD/MM/YYYY.'
END

Given the dates can go either way, we will have to build our query to assume the string is MM/DD/YYYY, unless the first two characters are greater than 12, then we will try DD/MM/YYYY instead.

Other Cases

While there are many other cases we could face, we can handle them all with the TRY..CATCH construct.  This was introduced with SQL 2005, but if you’ve worked with other languages you should recognize it.  This construct allows you to attempt something, and then catch the exception and either address the issue, or fail gracefully (instead of a critical failure.)  We can use the TRY..CATCH to attempt to case the VARCHAR as a DATETIME, and if that fails, we can fall back to our default case.

BEGIN TRY
  SELECT CONVERT(datetime, @varcharDateField) AS DateTimeField
END TRY
BEGIN CATCH
  SELECT NULL AS DateTimeField
END CATCH

Putting it all Together

Given each of these techniques, you could now build a SQL statement capable of converting most dates stored as VARCHAR into DATETIME.  While this is not exhaustive, you should have a good start.  Personally if I were building this, I would build this statement as a User Defined Function,  but you cannot use TRY..CATCH inside a user defined function.  So in order for you  be sure you were doing it the same way each time, you may try creating a PROCEDURE.

As always, if you have any questions feel free to send them in!

References

  • PATINDEX
  • LEN
  • LEFT
  • TRY .. CATCH

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Recent Posts

  • A New File Interrogator
  • Using Generative AI in Data Engineering
  • Getting started with Microsoft Fabric
  • Docker-based Spark
  • Network Infrastructure Updates

Recent Comments

  1. slowder on Data Engineering for Databricks
  2. Alex Ott on Data Engineering for Databricks

Archives

  • July 2023
  • June 2023
  • March 2023
  • February 2023
  • January 2023
  • December 2022
  • November 2022
  • October 2022
  • October 2018
  • August 2018
  • May 2018
  • February 2018
  • January 2018
  • November 2017
  • October 2017
  • September 2017
  • August 2017
  • June 2017
  • March 2017
  • February 2014
  • January 2014
  • December 2013
  • November 2013
  • October 2013
  • August 2013
  • July 2013
  • June 2013
  • February 2013
  • January 2013
  • August 2012
  • June 2012
  • May 2012
  • April 2012
  • March 2012
  • February 2012
  • January 2012
  • December 2011
  • November 2011
  • October 2011
  • September 2011
  • August 2011
  • July 2011
  • June 2011
  • May 2011
  • April 2011
  • March 2011
  • February 2011
  • January 2011
  • December 2010
  • November 2010
  • October 2010
  • September 2010
  • August 2010
  • July 2010
  • June 2010
  • May 2010
  • April 2010
  • March 2010
  • January 2010
  • December 2009
  • November 2009
  • October 2009
  • September 2009
  • August 2009
  • July 2009
  • June 2009
  • May 2009
  • April 2009
  • March 2009
  • February 2009
  • January 2009
  • December 2008
  • November 2008
  • October 2008
  • September 2008
  • August 2008
  • July 2008
  • June 2008
  • May 2008
  • April 2008
  • March 2008
  • February 2008
  • January 2008
  • November 2007
  • October 2007
  • September 2007
  • August 2007
  • July 2007
  • June 2007
  • May 2007
  • April 2007
  • March 2007
  • February 2007
  • January 2007
  • December 2006
  • November 2006
  • October 2006
  • September 2006
  • August 2006
  • July 2006
  • June 2006
  • May 2006
  • April 2006
  • March 2006
  • February 2006
  • January 2006
  • December 2005
  • November 2005
  • October 2005
  • September 2005
  • August 2005
  • July 2005
  • June 2005
  • May 2005
  • April 2005
  • March 2005
  • February 2005
  • January 2005
  • November 2004
  • September 2004
  • August 2004
  • July 2004
  • April 2004
  • March 2004
  • June 2002

Categories

  • Career Development
  • Data Engineering
  • Data Science
  • Infrastructure
  • Microsoft SQL
  • Modern Data Estate
  • Personal
  • Random Technology
  • uncategorized
© 2025 shannonlowder.com | Powered by Minimalist Blog WordPress Theme