The Problem: datetime stored as a float
You don't always get to choose your production software. Anytime a professional software product stores a date as a float it seems like someone should get a good scolding. There are rare occasions where a float is a necessary design decision, but that doesn't make it mean you need to enjoy working with that database.
When an application stores date information as a float it adds a level of complexity to otherwise standard querying -- one of the most confusing data types in SQL Server is datetime. This confusion leads to interesting conversations, as solutions involving datetime require specific attention to detail.
T-SQL handleds datetime strange, some of these issues are solved with the use of datetime2; however, certain limitations in my production enviroment made the use of datetime more appropriate.
The Solution
I have two problems to address
- Convert the float to datetime
- Ensure the data is semi-validated
Using a simple cast will sometimes toss an arithmetic overflow. Also, datetime is a strange beast, prone to fussy complications. To better address this, I took specific steps to ensure that the data picked apart and put together exactly as SQL Server expects datetime to be formed: 1900-01-01T00:01:00.000 (yyyy-mm-ddThh:mm:ss.mmm)
SELECT CASE WHEN (LEN(FLOOR(CAST(Float_Date AS BIGINT))) = 14) THEN CONVERT(datetime, ( LEFT(CAST(CAST(Float_Date as BigInt) as varchar(14)),4)+'-'+ SUBSTRING(CAST(CAST(Float_Date as BigInt) as varchar(14)),5,2)+'-'+ SUBSTRING(CAST(CAST(Float_Date as BigInt) as varchar(14)),7,2)+'T'+ SUBSTRING(CAST(CAST(Float_Date as BigInt) as varchar(14)),9,2)+':'+ SUBSTRING(CAST(CAST(Float_Date as BigInt) as varchar(14)),11,2)+':'+ SUBSTRING(CAST(CAST(Float_Date as BigInt) as varchar(14)),13,2)+'.000' )) ELSE NULL END AS Real_Date FROM dbo.ISSUES AS i
To explain how this works, review the pseudo code below:
Is the Float_Date field 14 numbers long? YES: Take the first 4 characters as year Add a '-' Then grab the next 2 characters as MM (Months) Add a '-' Then grab the next 2 characters as DD (Days) Then denote the time by adding 'T' Then grab the next 2 characters as HH (Hours) Add a ':' Then grab the next 2 characters as MM (Minutes) Add a ':' Then grab the next 2 characters as SS (Seconds) Then add '.000' as milliseconds Convert this as datetime NO: Set it as null.
For more information, check out MSDN.