user6001539
user6001539

Reputation: 53

SQL convert string(date or text) to date

I have a database which has a column called stringNextDue that contains data like dates (UK format) and text (e.g "overdue", "completed")

I am trying to create a view that shows courses that are due within a month from now:

WHERE 
    CONVERT(DATETIME, mt.stringNextDue , 103) < DATEADD(MONTH, 1, GETDATE())

This throws an error:

Conversion failed when converting date and/or time from character string.

Which is probably due to the fact that stringNextDue may contain actual strings of text.

I tried using

WHERE 
    ISDATE(mt.NextDateString) = 1 
    AND CONVERT(DATETIME, mt.stringNextDue , 103) < DATEADD(MONTH, 1, GETDATE())

But ISDATE only accepts US date formats therefore ignoring a lot of actual dates as strings

Tried set dateformat 'dmy', which fixed the IsDate issue, but it cannot be used in views.

Any suggestions?

Server update is not an option

Upvotes: 3

Views: 2023

Answers (3)

user6001539
user6001539

Reputation: 53

Thank you for suggestions,

I fixed it by setting language to British on user settings

EXEC sp_defaultlanguage 'username', 'british'

Upvotes: 0

t-clausen.dk
t-clausen.dk

Reputation: 44316

It should be possible to replace WHERE clause using this:

SELECT *
FROM 
  -- sample data
  (values('2015-01-01'),('01-01-2015'), ('x-x-x-x')) mt(NextDateString)
-- Replace WHERE statement with the following
CROSS APPLY
(
  SELECT
    RIGHT('0000'+PARSENAME(REPLACE(mt.NextDateString, '-', '.'), 1),4) yyy,
    RIGHT('0000'+PARSENAME(REPLACE(mt.NextDateString, '-', '.'), 2),4) mmm,
    RIGHT('0000'+PARSENAME(REPLACE(mt.NextDateString, '-', '.'), 3),4) ddd
) x
WHERE 
  x.yyy BETWEEN '1950' AND '2050'
  AND x.mmm BETWEEN '0001' AND '0012'
  AND x.ddd BETWEEN '0001' AND '0031'
  AND  ISDATE(mt.NextDateString) = 1
  AND x.yyy+x.mmm+x.ddd < CONVERT(char(8), DATEADD(MONTH, 1, GETDATE()), 112)

Result:

NextDateString  yyy   mmm   ddd
01-01-2015      2015  0001  0001

Upvotes: 0

Gottfried Lesigang
Gottfried Lesigang

Reputation: 67301

If you cannot use the new TRY_CONVERT you might use a function like this:

Attention: This will not catch a wrong date like 31.06.2016, you'd have to modify the BETWEEN 1 AND 31 if you need this...

Attention2: If your text might include characters forbidden in xml you should replace < with &lt;, > with &gt; and & with &amp; ...

CREATE FUNCTION dbo.TestDate(@TestString VARCHAR(100))
RETURNS DATE
AS
BEGIN
    DECLARE @x XML=CAST('<x>' + REPLACE(@TestString,'.','</x><x>') + '</x>' AS XML)

    DECLARE @p1 VARCHAR(10) = @x.value('x[1]','varchar(10)');
    DECLARE @p2 VARCHAR(10) = @x.value('x[2]','varchar(10)');
    DECLARE @p3 VARCHAR(10) = @x.value('x[3]','varchar(10)');

    IF    LEN(@p1)=2 AND ISNUMERIC(@p1)=1 AND CAST(@p1 AS INT) BETWEEN 1 AND 31
      AND LEN(@p2)=2 AND ISNUMERIC(@p2)=1 AND CAST(@p2 AS INT) BETWEEN 1 AND 12
      AND LEN(@p3)=4 AND ISNUMERIC(@p3)=1 AND CAST(@p3 AS INT) BETWEEN 1900 AND 2100

    RETURN CONVERT(DATETIME, @TestString , 103);

    RETURN NULL;
END
GO

SELECT
  dbo.TestDate('overdue') AS SureNoDate
 ,dbo.TestDate('01.04.2016') AS EuropeanDate
 ,dbo.TestDate('2016.04.01') AS WrongFormat
 ,dbo.TestDate('01.13.2016') AS BadDate;
GO

DROP FUNCTION dbo.TestDate;

The result

SureNoDate  EuropeanDate    WrongFormat BadDate
NULL        2016-04-01      NULL        NULL

You might pass back a valid date (RETURN GETDATE() ?) instead of RETURN NULL for your comparisson outside. This depends on your needs...

Upvotes: 2

Related Questions