problem using ISDATE in a Function

  • I have a function that uses ISDATE to determine whether a varchar passed in is valid.

    I know that the value of DATEFORMAT will alter the behaviour of ISDATE so how can I validate a date passed (knowing it's expected to be in DD/MM/YYYY HH:MM:SS).

    I really don't want to add my own date validation.

    I could take out the ISDATE, but if the date is invalid the function would error. Could I trap that error within the function nd then return a NULL?

    The actual function is:

    CREATE FUNCTION [fnDDMMYYYYHHMMSStoDate] (

    @inDDMMYYYYHHMMSS varchar(200)

    )

    RETURNS DateTime

    AS

    BEGIN

    DECLARE @outDate DateTime

    DECLARE @TextDate varchar(200)

    SELECT @TextDate = SUBSTRING(@inDDMMYYYYHHMMSS,7,4) + '-'

    + SUBSTRING(@inDDMMYYYYHHMMSS,4,2) + '-'

    + SUBSTRING(@inDDMMYYYYHHMMSS,1,2) + ' '

    + SUBSTRING(@inDDMMYYYYHHMMSS,12,8)

    -- Format of @TextDate is 'YYYY-MM-DD HH:MM:SS'

    IF LEN(@TextDate) <> 19 OR ISDATE(@TextDate) = 0

    BEGIN

    RETURN NULL

    END

    SELECT @outDate = CONVERT(datetime,@TextDate,120)

    RETURN @outDate

    END

    An example of the DATEFORMAT behaviour is:

    set dateformat mdy

    select ISDATE('2011-08-31 14:34:56')

    Returns 1

    set dateformat ymd

    select ISDATE('2011-08-31 14:34:56')

    Returns 1

    set dateformat dmy

    select ISDATE('2011-08-31 14:34:56')

    Returns 0

    I can't see an obvious answer to this one!

  • The only reference I have is BOL.

    Why the function return the data the way it does is beyond me.

    Regarding the function [fnDDMMYYYYHHMMSStoDate]:

    Wouldn't it be easier to simply use CONVERT (once the format is known)?

    DECLARE @val CHAR(19)

    SET @val='31/08/2011 14:34:56'

    SELECT CONVERT(DATETIME,@val,103)



    Lutz
    A pessimist is an optimist with experience.

    How to get fast answers to your question[/url]
    How to post performance related questions[/url]
    Links for Tally Table [/url] , Cross Tabs [/url] and Dynamic Cross Tabs [/url], Delimited Split Function[/url]

  • I accept that the function boils down to a CONVERT, but the problem is really about validating the string passed before calling CONVERT.

    Eg

    DECLARE @val CHAR(19)

    SET @val='08/31/2011 14:34:56'

    SELECT CONVERT(DATETIME,@val,103)

    fails with

    The conversion of a char data type to a datetime data type resulted in an out-of-range datetime value.

    Validating the date string with ISDATE will depend on the value of DATEFORMAT, but I can't change it's vaue in the function.

    Is there a way of handling the error from the CONVERT from within the function?

  • RichardBo (9/22/2011)


    I accept that the function boils down to a CONVERT, but the problem is really about validating the string passed before calling CONVERT.

    Eg

    DECLARE @val CHAR(19)

    SET @val='08/31/2011 14:34:56'

    SELECT CONVERT(DATETIME,@val,103)

    fails with

    The conversion of a char data type to a datetime data type resulted in an out-of-range datetime value.

    Validating the date string with ISDATE will depend on the value of DATEFORMAT, but I can't change it's vaue in the function.

    Is there a way of handling the error from the CONVERT from within the function?

    I have a CLR that allows me to do RegEx in my database.

    USE [Test]

    GO

    IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ReplaceMatch]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))

    DROP FUNCTION [dbo].[ReplaceMatch]

    GO

    IF EXISTS (SELECT * FROM sys.assemblies asms WHERE asms.name = N'RegEx' and is_user_defined = 1)

    DROP ASSEMBLY [RegEx]

    GO

    USE [Test]

    GO

    CREATE ASSEMBLY [RegEx]

    AUTHORIZATION [dbo]

    FROM 0x4D5A90000300000004000000FFFF0000B800000000000000400000000000000000000000000000000000000000000000000000000000000000000000800000000E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F742062652072756E20696E20444F53206D6F64652E0D0D0A2400000000000000504500004C010300604E7B4E0000000000000000E00002210B010800000A000000060000000000002E280000002000000040000000004000002000000002000004000000000000000400000000000000008000000002000000000000030040850000100000100000000010000010000000000000100000000000000000000000E02700004B000000004000006003000000000000000000000000000000000000006000000C000000542700001C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000080000000000000000000000082000004800000000000000000000002E746578740000003408000000200000000A000000020000000000000000000000000000200000602E72737263000000600300000040000000040000000C0000000000000000000000000000400000402E72656C6F6300000C000000006000000002000000100000000000000000000000000000400000420000000000000000000000000000000010280000000000004800000002000500FC2000005806000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001B300300870000000100001100000F00280F00000A2D120F01280F00000A2D090F02280F00000A2B01170B072D40000F00281000000A0F01281000000A281100000A16FE010B072D220F00281000000A0F01281000000A0F02281000000A281200000A281300000A0ADE25002B087E1400000A0ADE1A00DE0A26007E1400000A0ADE0D001202FE1502000001080A2B0000062A0001100000000001006C6D000A010000011E02281500000A2A42534A4201000100000000000C00000076322E302E35303732370000000005006C0000001C020000237E000088020000EC02000023537472696E6773000000007405000008000000235553007C0500001000000023475549440000008C050000CC00000023426C6F620000000000000002000001471502000900000000FA2533001600000100000012000000020000000200000003000000150000000C00000001000000010000000300000000000A0001000000000006002A0023000A0052003D000600AD009B000600C4009B000600E1009B00060000019B00060019019B00060032019B0006004D019B00060068019B000600A00181010600B4019B000600E001CD013700F40100000600230203020600430203020A007C0261020E00C502A6020000000001000000000001000100010010001400140005000100010050200000000096005C000A000100F420000000008618690015000400000001006F00000002007B00000003008800190069001900210069001900290069001900310069001900390069001900410069001900490069001900510069001900590069001E0061006900190069006900230079006900290081006900150089006900150011009102330011009C0237009100CB023B009100D30241001100DB0248001100E7024E00090069001500200073002E002E002B005A002E00130065002E001B0065002E0023006B002E000B005A002E0033007A002E003B0065002E004B0065002E005B009B002E006300A4002E006B00AD0052000480000001000000BA10F0690000000000001400000002000000000000000000000001001A0000000000020000000000000000000000010031000000000002000000000000000000000001002300000000000000003C4D6F64756C653E0052656745782E646C6C005265674578006D73636F726C69620053797374656D004F626A6563740053797374656D2E446174610053797374656D2E446174612E53716C54797065730053716C537472696E67005265706C6163654D61746368002E63746F7200696E707574537472696E67006D617463685061747465726E007265706C6163656D656E745061747465726E0053797374656D2E5265666C656374696F6E00417373656D626C795469746C6541747472696275746500417373656D626C794465736372697074696F6E41747472696275746500417373656D626C79436F6E66696775726174696F6E41747472696275746500417373656D626C79436F6D70616E7941747472696275746500417373656D626C7950726F6475637441747472696275746500417373656D626C79436F7079726967687441747472696275746500417373656D626C7954726164656D61726B41747472696275746500417373656D626C7943756C747572654174747269627574650053797374656D2E52756E74696D652E496E7465726F70536572766963657300436F6D56697369626C6541747472696275746500417373656D626C7956657273696F6E4174747269627574650053797374656D2E446961676E6F73746963730044656275676761626C6541747472696275746500446562756767696E674D6F6465730053797374656D2E52756E74696D652E436F6D70696C6572536572766963657300436F6D70696C6174696F6E52656C61786174696F6E734174747269627574650052756E74696D65436F6D7061746962696C697479417474726962757465004D6963726F736F66742E53716C5365727665722E5365727665720053716C46756E6374696F6E417474726962757465006765745F49734E756C6C006765745F56616C75650053797374656D2E546578742E526567756C617245787072657373696F6E730052656765780049734D61746368005265706C616365006F705F496D706C69636974004E756C6C0000032000000000001E78D965909B314580DBFD0A7B0352280008B77A5C561934E0890A0003110911091109110903200001042001010E042001010205200101113904200101080401000000032000020320000E050002020E0E0600030E0E0E0E05000111090E0306110907070311090211090A010005526567457800000501000000000E0100094D6963726F736F667400002001001B436F7079726967687420C2A9204D6963726F736F6674203230313100000801000701000000000801000800000000001E01000100540216577261704E6F6E457863657074696F6E5468726F77730100000000604E7B4E00000000020000006E0000007027000070090000525344531B7CA5D062A8E844BB3B65F9037A19C002000000633A5C75736572735C6372616967775C646F63756D656E74735C76697375616C2073747564696F20323031305C50726F6A656374735C52656745785C52656745785C6F626A5C44656275675C52656745782E7064620000000828000000000000000000001E280000002000000000000000000000000000000000000000000000102800000000000000005F436F72446C6C4D61696E006D73636F7265652E646C6C0000000000FF25002040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100100000001800008000000000000000000000000000000100010000003000008000000000000000000000000000000100000000004800000058400000080300000000000000000000080334000000560053005F00560045005200530049004F004E005F0049004E0046004F0000000000BD04EFFE0000010000000100F069BA1000000100F069BA103F000000000000000400000002000000000000000000000000000000440000000100560061007200460069006C00650049006E0066006F00000000002400040000005400720061006E0073006C006100740069006F006E00000000000000B00468020000010053007400720069006E006700460069006C00650049006E0066006F00000044020000010030003000300030003000340062003000000034000A00010043006F006D00700061006E0079004E0061006D006500000000004D006900630072006F0073006F00660074000000340006000100460069006C0065004400650073006300720069007000740069006F006E000000000052006500670045007800000040000F000100460069006C006500560065007200730069006F006E000000000031002E0030002E0034003200380032002E00320037003100320030000000000034000A00010049006E007400650072006E0061006C004E0061006D0065000000520065006700450078002E0064006C006C0000005C001B0001004C006500670061006C0043006F007000790072006900670068007400000043006F0070007900720069006700680074002000A90020004D006900630072006F0073006F006600740020003200300031003100000000003C000A0001004F0072006900670069006E0061006C00460069006C0065006E0061006D0065000000520065006700450078002E0064006C006C0000002C0006000100500072006F0064007500630074004E0061006D0065000000000052006500670045007800000044000F000100500072006F006400750063007400560065007200730069006F006E00000031002E0030002E0034003200380032002E00320037003100320030000000000048000F00010041007300730065006D0062006C0079002000560065007200730069006F006E00000031002E0030002E0034003200380032002E00320037003100320030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000C000000303800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

    WITH PERMISSION_SET = SAFE

    GO

    CREATE FUNCTION [dbo].[ReplaceMatch](@inputString [nvarchar](4000), @matchPattern [nvarchar](4000), @replacementPattern [nvarchar](4000))

    RETURNS [nvarchar](4000) WITH EXECUTE AS CALLER

    AS

    EXTERNAL NAME [RegEx].[RegEx.RegEx].[ReplaceMatch]

    GO

    The code is nothing special: -

    using Microsoft.SqlServer.Server;

    using System.Data.SqlTypes;

    using System.Text.RegularExpressions;

    // namespace to work with regular expressions

    namespace RegEx

    {

    public class RegEx

    {

    [SqlFunction]

    public static SqlString ReplaceMatch(

    SqlString inputString,

    SqlString matchPattern,

    SqlString replacementPattern)

    {

    try

    {

    // input parameters must not be NULL

    if (!inputString.IsNull &&

    !matchPattern.IsNull &&

    !replacementPattern.IsNull)

    {

    // check for first pattern match

    if (Regex.IsMatch(inputString.Value,

    matchPattern.Value))

    // match found, replace using second pattern and return result

    return Regex.Replace(inputString.Value,

    matchPattern.Value,

    replacementPattern.Value);

    }

    else

    // if any input paramater is NULL, return NULL

    return SqlString.Null;

    }

    catch

    {

    // on any error, return NULL

    return SqlString.Null;

    }

    return new SqlString();

    }

    };

    }

    This now allows you to run the following: -

    DECLARE @val CHAR(19)

    SET @val='31/08/2011 14:34:56'

    SELECT CONVERT(DATETIME,(dbo.ReplaceMatch(@val,

    '(?n:^(?=\d)((?<day>31(?!(.0?[2469]|11))|30(?!.0?2)|

    29(?(.0?2)(?=.{3,4}(1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|

    (16|[2468][048]|[3579][26])00))|0?[1-9]|1\d|2[0-8])(?<sep>[/.-])(?<month>0?[1-9]|1[012])\2(?<year>(1[6-9]|[2-9]\d)\d{2})(?:

    (?=\x20\d)\x20|$))?(?<time>((0?[1-9]|1[012])(:[0-5]\d){0,2}(?i:\ [AP]M))|([01]\d|2[0-3])(:[0-5]\d){1,2})?$)',

    @val)),103)

    The regular expression validates the date, so in the above case it returns "NULL".

    --EDIT--

    Hmm, my SQL code block managed to have a smiley in it. . . corrected 🙂


    Forever trying to learn
    My blog - http://www.cadavre.co.uk/
    For better, quicker answers on T-SQL questions, click on the following...http://www.sqlservercentral.com/articles/Best+Practices/61537/
    For better, quicker answers on SQL Server performance related questions, click on the following...http://www.sqlservercentral.com/articles/SQLServerCentral/66909/

  • Well, since you can't use a TRY-CATCH construct in a user-defined function and you can't use SET DATEFORMAT in a user-defined function, either, what about setting up the code that calls the function to use a TRY-CATCH construct to change the DATEFORMAT setting depending on whether the function executes properly or returns an error?

    Here's the function I created to test this idea:

    CREATE FUNCTION dbo.test_date_convert (@test_date char(19))

    RETURNS DATETIME

    AS

    BEGIN

    DECLARE @return_date datetime

    SET @return_date = CAST(@test_date as datetime)

    RETURN @return_date

    END

    I used CAST instead of CONVERT here since CASTing character strings to datetimes sometimes works with certain DATEFORMAT settings and string values when CONVERTing them would not. You can't specify a style with CAST, but many people would argue that applying a style to a datetime value should be done by the application layer anyway.

    Here's the code I used to call the function in nested TRY-CATCH blocks that change the DATEFORMAT when the function call returns the error:

    DECLARE @test_date char(19), @result_date datetime

    SET @test_date = '31-08-2011 14:36:24'

    BEGIN TRY

    SET DATEFORMAT mdy

    SET @result_date = dbo.test_date_convert(@test_date)

    PRINT 'TRY SUCCEEDED'

    END TRY

    BEGIN CATCH

    BEGIN TRY

    SET DATEFORMAT dmy

    SET @result_date = dbo.test_date_convert(@test_date)

    PRINT 'CATCH 1 SUCCEEDED'

    END TRY

    BEGIN CATCH

    SET DATEFORMAT ymd

    SET @result_date = dbo.test_date_convert(@test_date)

    PRINT 'CATCH 2 SUCCEEDED'

    END CATCH

    END CATCH

    SELECT @result_date

    I tried it with all different combinations of MM-DD-YYYY, DD-MM-YYYY, and YYYY-MM-DD string formats (using both '-' and '/' as a separator) and got the desired result each time. It does appear that the second TRY-CATCH is probably superfluous because the function can CAST YYYY-MM-DD strings to datetime when DATEFORMAT is mdy.

    I don't know if you can implement this idea in your calling code, but if you have no way to validate the format of the date strings being passed to the database, I'm not sure what else you can do to handle datatype conversion errors.

    Jason Wolfkill

  • Thank you for your thoughts. It seems that there isn't an easy way to validate a date within a function (if ISDATE doesn't work for you). The CLR solution is neat as long as you don't have to revisit it and understand what to do with it.

    What I decided to do is create a table with each valid date in it. Validating a date then just becomes SELECT Date FROM Dates WHERE DDMMMYYYY = '<Value>' it returns nothing if it's not valid and the date if it is.

    It also gives me additional benefits of having a valid range for my dates.

  • RichardBo (9/27/2011)


    Thank you for your thoughts. It seems that there isn't an easy way to validate a date within a function (if ISDATE doesn't work for you). The CLR solution is neat as long as you don't have to revisit it and understand what to do with it.

    What I decided to do is create a table with each valid date in it. Validating a date then just becomes SELECT Date FROM Dates WHERE DDMMMYYYY = '<Value>' it returns nothing if it's not valid and the date if it is.

    It also gives me additional benefits of having a valid range for my dates.

    This seems like a good solution to me, especially if you have a limited range of acceptable dates. I re-read your original post, though, and noticed that you said the varchar() value "is expected" to be passed as DDMMYYYY (with some time info, too). Does the application that passes the varchar() value strictly control the format, and can you ensure that it always will? Otherwise, can you be sure that 01082011 is 01 Aug 2011 and not 08 Jan 2011? Needless to say, this kind of confusion and uncertainty would cause a world of hurt. This is one of the many reasons that experienced database developers recommend against accepting, storing, and returning dates as varchar() data types and, if that is unavoidable, to insist on an ISO 8601 compliant format (e.g., YYYYMMDD, YYYY-MM-DD) so that there is no ambiguity.

    Best wishes,

    JW

    Jason Wolfkill

  • While the solution worked (using a table of dates) it was very slow when used on large tables so has been scrapped.

    I have found a method that does what I want -

    I am expecting the date passed to be in the format DD/MM/YYYY and change it to YYYY-MM-DD before the CONVERT(DateTime,@d,120) which works whatever the DATEFORMAT.

    I have found that ISDATE will return 1 for at least 1 of the two formats (DD/MM/YYYY and YYYY-MM-DD) if the date is valid for any value of DATEFORMAT.

    I call ISDATE for both date formats. If one returns 1, the date is valid.

    This little test shows the problem:

    set dateformat DMY

    select ISDATE('23/12/2010') AS DMY

    ,ISDATE('2010-12-23')

    set dateformat DYM

    select ISDATE('23/12/2010') AS DMY

    ,ISDATE('2010-12-23')

    set dateformat MYD

    select ISDATE('23/12/2010') AS DMY

    ,ISDATE('2010-12-23')

    set dateformat MDY

    select ISDATE('23/12/2010') AS DMY

    ,ISDATE('2010-12-23')

    set dateformat YMD

    select ISDATE('23/12/2010') AS DMY

    ,ISDATE('2010-12-23')

    set dateformat YDM

    select ISDATE('23/12/2010') AS DMY

    ,ISDATE('2010-12-23')

    The function is written to convert a varchar in the format DD/MM/YYYY into a DateTime exactly because I want it stored as a DateTime and not a varchar - I am an experienced database developer. I don't have the luxury of dictating the format the date will be passed to me in this instance.

  • I certainly sympathize with you for having to work with suboptimal requirements with no ability to change them!

    Do you really need the hyphen separators when you convert @inDDMMYYYYHHMMSS to @TextDate? If you leave them out, @TextDate will be in ISO 8601 basic format (YYYYDDMM, e.g., '20110930'). ISDATE() works correctly on character strings in ISO 8601 basic format (with or without time data) regardless of the DATEFORMAT setting.

    If you format @TextDate without the hyphen separators, I think this SELECT statement, used as the heart of your function, would meet your requirements:

    select @outDate = CASE WHEN LEN(@TextDate) = 17 and ISDATE(@TextDate) = 1

    THEN CONVERT(datetime, @TextDate, 120)

    ELSE NULL

    END

    The CASE expression ensures that the CONVERT() function never tries to operate on a varchar() value that would give an out-of-range error, returning NULL when either condition (LEN(@TextDate) = 17 and ISDATE(@TextDate)) evaluates to FALSE. If you want to allow dates without time information to be inserted as the date with time set to 00:00:00.000, you could leave out the LEN(@TextDate) condition.

    Jason Wolfkill

  • I still prefer the CLR method personally 🙂

    I quickly knocked up a simple date-validation C# CLR that should suffice. I realise you have your solution, just an offering for the great Google when others are searching for this topic. The code is nothing special, again, so is easy to follow.

    It validates dates in either dd/MM/yyyy or MM/dd/yyyy format and will validate with or without the time.

    using System;

    using Microsoft.SqlServer.Server;

    using System.Data.SqlTypes;

    using System.Text.RegularExpressions;

    namespace DateValidation

    {

    public class DateValidation

    {

    [SqlFunction]

    public static SqlString ValidateDate(

    SqlString dateString,

    SqlString datePattern)

    {

    try

    {

    var regDate = "";

    if (datePattern.Value == "dd/MM/yyyy")

    {

    regDate = @"(?n:^(?=\d)((?<day>31(?!(.0?[2469]|11))|30(?!.0?2)|29(?(.0?2)(?=.{3,4}(1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|(16|[2468][048]|[3579][26])00))|0?[1-9]|1\d|2[0-8])(?<sep>[/.-])(?<month>0?[1-9]|1[012])\2(?<year>(1[6-9]|[2-9]\d)\d{2})(?:(?=\x20\d)\x20|$))?(?<time>((0?[1-9]|1[012])(:[0-5]\d){0,2}(?i:\ [AP]M))|([01]\d|2[0-3])(:[0-5]\d){1,2})?$)";

    }

    if (datePattern.Value == "MM/dd/yyyy")

    {

    regDate = @"(?n:^(?=\d)((?<month>0?[1-9]|1[012])(?<sep>[/.-])(?<day>31(?!(.0?[2469]|11))|30(?!.0?2)|29(?(.0?2)(?=.{3,4}(1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|(16|[2468][048]|[3579][26])00))|0?[1-9]|1\d|2[0-8])\2(?<year>(1[6-9]|[2-9]\d)\d{2})(?:(?=\x20\d)\x20|$))?(?<time>((0?[1-9]|1[012])(:[0-5]\d){0,2}(?i:\ [AP]M))|([01]\d|2[0-3])(:[0-5]\d){1,2})?$)";

    }

    //if datePattern is not empty or null and dateString is not empty of null

    //then check to see if the regEx matches the dateString. If it matches, return the

    //dateString.

    //If any of the above is not true, return null.

    return Regex.IsMatch(dateString.Value, regDate) && !string.IsNullOrEmpty(datePattern.Value) && !string.IsNullOrEmpty(dateString.Value) ? dateString.Value : SqlString.Null;

    }

    catch (Exception e)

    {

    // on any error, return NULL

    return SqlString.Null;

    //return e.Message;

    }

    }

    }

    }

    USE [Test]

    GO

    IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ValidateDate]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))

    DROP FUNCTION [dbo].[ValidateDate]

    GO

    USE [Test]

    GO

    IF EXISTS (SELECT * FROM sys.assemblies asms WHERE asms.name = N'DateValidation' and is_user_defined = 1)

    DROP ASSEMBLY [DateValidation]

    GO

    USE [Test]

    GO

    CREATE ASSEMBLY [DateValidation]

    AUTHORIZATION [dbo]

    FROM 0x4D5A90000300000004000000FFFF0000B800000000000000400000000000000000000000000000000000000000000000000000000000000000000000800000000E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F742062652072756E20696E20444F53206D6F64652E0D0D0A2400000000000000504500004C010300E2DF854E0000000000000000E00002210B010800001000000006000000000000FE2D0000002000000040000000004000002000000002000004000000000000000400000000000000008000000002000000000000030040850000100000100000000010000010000000000000100000000000000000000000A82D000053000000004000006003000000000000000000000000000000000000006000000C0000001C2D00001C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000080000000000000000000000082000004800000000000000000000002E74657874000000040E0000002000000010000000020000000000000000000000000000200000602E7273726300000060030000004000000004000000120000000000000000000000000000400000402E72656C6F6300000C0000000060000000020000001600000000000000000000000000004000004200000000000000000000000000000000E02D00000000000048000000020005000C210000100C000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001B3002009600000001000011000072010000700A0F01280F00000A7203000070281000000A16FE010D092D080072190000700A000F01280F00000A72D4020070281000000A16FE010D092D080072EA0200700A000F00280F00000A06281100000A2C1C0F01280F00000A281200000A2D0E0F00280F00000A281200000A2C077E1300000A2B0C0F00280F00000A281400000A0CDE0A0B007E1300000A0CDE0000082A000001100000000001008889000A140000011E02281500000A2A42534A4201000100000000000C00000076322E302E35303732370000000005006C00000024020000237E0000900200000003000023537472696E67730000000090050000A805000023555300380B0000100000002347554944000000480B0000C800000023426C6F620000000000000002000001471502000900000000FA2533001600000100000014000000020000000200000002000000150000000C00000001000000010000000300000000000A00010000000000060033002C000A005B0046000600A1008F000600B8008F000600D5008F000600F4008F0006000D018F00060026018F00060041018F0006005C018F000600940175010600A8018F000600D401C1013700E801000006001702F70106003702F7010A0076025B02060095022C000E00C702A8020600F4022C0000000000010000000000010001000100100014001400050001000100502000000000960065000A0001000421000000008618720013000300000001007800000002008300190072001700210072001700290072001700310072001700390072001700410072001700490072001700510072001700590072001C0061007200170069007200210079007200270081007200130089007200130011008B02310091009C0235009900CD0235009100D5023B001100E30240001100E8024400090072001300200073002C002E002B0053002E0013005E002E001B005E002E00230064002E000B0053002E00330073002E003B005E002E004B005E002E005B0094002E0063009D002E006B00A6004A000480000001000000C210B16C00000000000055020000020000000000000000000000010023000000000002000000000000000000000001003A000000000002000000000000000000000001002C000000000000000000003C4D6F64756C653E0052656745782E646C6C004461746556616C69646174696F6E006D73636F726C69620053797374656D004F626A6563740053797374656D2E446174610053797374656D2E446174612E53716C54797065730053716C537472696E670056616C696461746544617465002E63746F720064617465537472696E6700646174655061747465726E0053797374656D2E5265666C656374696F6E00417373656D626C795469746C6541747472696275746500417373656D626C794465736372697074696F6E41747472696275746500417373656D626C79436F6E66696775726174696F6E41747472696275746500417373656D626C79436F6D70616E7941747472696275746500417373656D626C7950726F6475637441747472696275746500417373656D626C79436F7079726967687441747472696275746500417373656D626C7954726164656D61726B41747472696275746500417373656D626C7943756C747572654174747269627574650053797374656D2E52756E74696D652E496E7465726F70536572766963657300436F6D56697369626C6541747472696275746500417373656D626C7956657273696F6E4174747269627574650053797374656D2E446961676E6F73746963730044656275676761626C6541747472696275746500446562756767696E674D6F6465730053797374656D2E52756E74696D652E436F6D70696C6572536572766963657300436F6D70696C6174696F6E52656C61786174696F6E734174747269627574650052756E74696D65436F6D7061746962696C697479417474726962757465005265674578004D6963726F736F66742E53716C5365727665722E5365727665720053716C46756E6374696F6E417474726962757465006765745F56616C756500537472696E67006F705F457175616C6974790053797374656D2E546578742E526567756C617245787072657373696F6E730052656765780049734D617463680049734E756C6C4F72456D707479004E756C6C006F705F496D706C6963697400457863657074696F6E00000000010015640064002F004D004D002F0079007900790079000082B928003F006E003A005E0028003F003D005C0064002900280028003F003C006400610079003E003300310028003F00210028002E0030003F005B0032003400360039005D007C0031003100290029007C003300300028003F0021002E0030003F00320029007C003200390028003F0028002E0030003F003200290028003F003D002E007B0033002C0034007D00280031005B0036002D0039005D007C005B0032002D0039005D005C0064002900280030005B00340038005D007C005B0032003400360038005D005B003000340038005D007C005B00310033003500370039005D005B00320036005D0029007C002800310036007C005B0032003400360038005D005B003000340038005D007C005B0033003500370039005D005B00320036005D00290030003000290029007C0030003F005B0031002D0039005D007C0031005C0064007C0032005B0030002D0038005D00290028003F003C007300650070003E005B002F002E002D005D00290028003F003C006D006F006E00740068003E0030003F005B0031002D0039005D007C0031005B003000310032005D0029005C00320028003F003C0079006500610072003E00280031005B0036002D0039005D007C005B0032002D0039005D005C00640029005C0064007B0032007D00290028003F003A0028003F003D005C007800320030005C00640029005C007800320030007C002400290029003F0028003F003C00740069006D0065003E002800280030003F005B0031002D0039005D007C0031005B003000310032005D00290028003A005B0030002D0035005D005C00640029007B0030002C0032007D0028003F0069003A005C0020005B00410050005D004D00290029007C0028005B00300031005D005C0064007C0032005B0030002D0033005D00290028003A005B0030002D0035005D005C00640029007B0031002C0032007D0029003F002400290001154D004D002F00640064002F0079007900790079000082B928003F006E003A005E0028003F003D005C0064002900280028003F003C006D006F006E00740068003E0030003F005B0031002D0039005D007C0031005B003000310032005D00290028003F003C007300650070003E005B002F002E002D005D00290028003F003C006400610079003E003300310028003F00210028002E0030003F005B0032003400360039005D007C0031003100290029007C003300300028003F0021002E0030003F00320029007C003200390028003F0028002E0030003F003200290028003F003D002E007B0033002C0034007D00280031005B0036002D0039005D007C005B0032002D0039005D005C0064002900280030005B00340038005D007C005B0032003400360038005D005B003000340038005D007C005B00310033003500370039005D005B00320036005D0029007C002800310036007C005B0032003400360038005D005B003000340038005D007C005B0033003500370039005D005B00320036005D00290030003000290029007C0030003F005B0031002D0039005D007C0031005C0064007C0032005B0030002D0038005D0029005C00320028003F003C0079006500610072003E00280031005B0036002D0039005D007C005B0032002D0039005D005C00640029005C0064007B0032007D00290028003F003A0028003F003D005C007800320030005C00640029005C007800320030007C002400290029003F0028003F003C00740069006D0065003E002800280030003F005B0031002D0039005D007C0031005B003000310032005D00290028003A005B0030002D0035005D005C00640029007B0030002C0032007D0028003F0069003A005C0020005B00410050005D004D00290029007C0028005B00300031005D005C0064007C0032005B0030002D0033005D00290028003A005B0030002D0035005D005C00640029007B0031002C0032007D0029003F002400290001000000DDAA378342407A4AAE02071092FA99B70008B77A5C561934E08908000211091109110903200001042001010E0420010102052001011139042001010804010000000320000E050002020E0E040001020E0306110905000111090E0807040E12511109020A010005526567457800000501000000000E0100094D6963726F736F667400002001001B436F7079726967687420C2A9204D6963726F736F6674203230313100000801000701000000000801000800000000001E01000100540216577261704E6F6E457863657074696F6E5468726F77730100000000000000E2DF854E00000000020000006E000000382D0000380F0000525344531B7CA5D062A8E844BB3B65F9037A19C00F000000433A5C55736572735C6372616967775C446F63756D656E74735C56697375616C2053747564696F20323031305C50726F6A656374735C52656745785C52656745785C6F626A5C44656275675C52656745782E706462000000D02D00000000000000000000EE2D0000002000000000000000000000000000000000000000000000E02D000000000000000000000000000000005F436F72446C6C4D61696E006D73636F7265652E646C6C0000000000FF25002040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100100000001800008000000000000000000000000000000100010000003000008000000000000000000000000000000100000000004800000058400000080300000000000000000000080334000000560053005F00560045005200530049004F004E005F0049004E0046004F0000000000BD04EFFE0000010000000100B16CC21000000100B16CC2103F000000000000000400000002000000000000000000000000000000440000000100560061007200460069006C00650049006E0066006F00000000002400040000005400720061006E0073006C006100740069006F006E00000000000000B00468020000010053007400720069006E006700460069006C00650049006E0066006F00000044020000010030003000300030003000340062003000000034000A00010043006F006D00700061006E0079004E0061006D006500000000004D006900630072006F0073006F00660074000000340006000100460069006C0065004400650073006300720069007000740069006F006E000000000052006500670045007800000040000F000100460069006C006500560065007200730069006F006E000000000031002E0030002E0034003200390030002E00320037003800320035000000000034000A00010049006E007400650072006E0061006C004E0061006D0065000000520065006700450078002E0064006C006C0000005C001B0001004C006500670061006C0043006F007000790072006900670068007400000043006F0070007900720069006700680074002000A90020004D006900630072006F0073006F006600740020003200300031003100000000003C000A0001004F0072006900670069006E0061006C00460069006C0065006E0061006D0065000000520065006700450078002E0064006C006C0000002C0006000100500072006F0064007500630074004E0061006D0065000000000052006500670045007800000044000F000100500072006F006400750063007400560065007200730069006F006E00000031002E0030002E0034003200390030002E00320037003800320035000000000048000F00010041007300730065006D0062006C0079002000560065007200730069006F006E00000031002E0030002E0034003200390030002E00320037003800320035000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000C000000003E00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

    WITH PERMISSION_SET = SAFE

    GO

    USE [Test]

    GO

    CREATE FUNCTION [dbo].[ValidateDate](@dateString [nvarchar](4000), @datePattern [nvarchar](4000))

    RETURNS [nvarchar](4000) WITH EXECUTE AS CALLER

    AS

    EXTERNAL NAME [DateValidation].[DateValidation.DateValidation].[ValidateDate]

    GO

    --EDIT--

    For some reason, it keeps adding smiley faces to the RegEx.

    dd/MM/yyyy

    (?n:^(?=\d)((?<day>31(?!(.0?[2469]|11))|30(?!.0?2)|29(?(.0?2)(?=.{3,4}(1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|(16|[2468][048]|[3579][26])00))|0?[1-9]|1\d|2[0-8])(?<sep>[/.-])(?<month>0?[1-9]|1[012])\2(?<year>(1[6-9]|[2-9]\d)\d{2})(?:

    (?=\x20\d)\x20|$))?(?<time>((0?[1-9]|1[012])(:[0-5]\d){0,2}(?i:\ [AP]M))|([01]\d|2[0-3])(:[0-5]\d){1,2})?$)

    MM/dd/yyyy

    (?n:^(?=\d)((?<month>0?[1-9]|1[012])(?<sep>[/.-])(?<day>31(?!(.0?[2469]|11))|30(?!.0?2)|29(?(.0?2)(?=.{3,4}(1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|(16|[2468][048]|[3579][26])00))|0?[1-9]|1\d|2[0-8])\2(?<year>(1[6-9]|[2-9]\d)\d{2})(?:

    (?=\x20\d)\x20|$))?(?<time>((0?[1-9]|1[012])(:[0-5]\d){0,2}(?i:\ [AP]M))|([01]\d|2[0-3])(:[0-5]\d){1,2})?$)


    Forever trying to learn
    My blog - http://www.cadavre.co.uk/
    For better, quicker answers on T-SQL questions, click on the following...http://www.sqlservercentral.com/articles/Best+Practices/61537/
    For better, quicker answers on SQL Server performance related questions, click on the following...http://www.sqlservercentral.com/articles/SQLServerCentral/66909/

  • wolfkillj (9/30/2011)


    I certainly sympathize with you for having to work with suboptimal requirements with no ability to change them!

    Do you really need the hyphen separators when you convert @inDDMMYYYYHHMMSS to @TextDate? If you leave them out, @TextDate will be in ISO 8601 basic format (YYYYDDMM, e.g., '20110930'). ISDATE() works correctly on character strings in ISO 8601 basic format (with or without time data) regardless of the DATEFORMAT setting.

    Actually, you could just go with full ISO 8601 format, thusly: '2011-09-01T13:37:44'

    From BOL:

    The advantage in using the ISO 8601 format is that it is an international standard. Date and time values that are specified by using this format are unambiguous. This format is not affected by the SET DATEFORMAT, SET LANGUAGE, of login default language settings.

    http://msdn.microsoft.com/en-us/library/ms180878.aspx#ISO8601Format

    Jason Wolfkill

  • Here is a fairly simple check that will work with any setting of DATEFIRST:

    select

    a.dt,

    IsValidDateTime =

    case

    -- Check that date string is in correct format, mm/dd/yyyy hh:mm:ss

    when dt not like '[0-1][0-9]/[0-3][0-9]/[1-9][0-9][0-9][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9]'

    then 0

    -- Reformat and test date in universal format of yyyymmdd hh:mm:ss

    when isdate(substring(a.dt,7,4)+substring(a.dt,1,2)+substring(a.dt,4,2)+substring(a.dt,11,9)) <> 1

    then 0

    else 1

    end

    from

    ( -- Test Data

    select dt = '08/31/2001 14:34:56'union all

    select dt = '08/31/2001 34:34:56'union all

    select dt = '08/31/2001 14:64:56'union all

    select dt = '08/31/2001 14:34:66'union all

    select dt = '08/31/2001 25:34:56'union all

    select dt = '08/31/2001 14:34:56'union all

    select dt = '13/01/2001 14:34:56'union all

    select dt = '0a/31/2001 14:34:56'union all

    select dt = '08/32/2001 14:34:56'union all

    select dt = '21/31/2001 14:34:56'

    ) a

    Results:

    dt IsValidDateTime

    ------------------- ---------------

    08/31/2001 14:34:56 1

    08/31/2001 34:34:56 0

    08/31/2001 14:64:56 0

    08/31/2001 14:34:66 0

    08/31/2001 25:34:56 0

    08/31/2001 14:34:56 1

    13/01/2001 14:34:56 0

    0a/31/2001 14:34:56 0

    08/32/2001 14:34:56 0

    21/31/2001 14:34:56 0

    (10 row(s) affected)

  • Michael Valentine Jones (9/30/2011)


    Here is a fairly simple check that will work with any setting of DATEFIRST:

    select

    a.dt,

    IsValidDateTime =

    case

    -- Check that date string is in correct format, mm/dd/yyyy hh:mm:ss

    when dt not like '[0-1][0-9]/[0-3][0-9]/[1-9][0-9][0-9][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9]'

    then 0

    -- Reformat and test date in universal format of yyyymmdd hh:mm:ss

    when isdate(substring(a.dt,7,4)+substring(a.dt,1,2)+substring(a.dt,4,2)+substring(a.dt,11,9)) <> 1

    then 0

    else 1

    end

    from

    ( -- Test Data

    select dt = '08/31/2001 14:34:56'union all

    select dt = '08/31/2001 34:34:56'union all

    select dt = '08/31/2001 14:64:56'union all

    select dt = '08/31/2001 14:34:66'union all

    select dt = '08/31/2001 25:34:56'union all

    select dt = '08/31/2001 14:34:56'union all

    select dt = '13/01/2001 14:34:56'union all

    select dt = '0a/31/2001 14:34:56'union all

    select dt = '08/32/2001 14:34:56'union all

    select dt = '21/31/2001 14:34:56'

    ) a

    Results:

    dt IsValidDateTime

    ------------------- ---------------

    08/31/2001 14:34:56 1

    08/31/2001 34:34:56 0

    08/31/2001 14:64:56 0

    08/31/2001 14:34:66 0

    08/31/2001 25:34:56 0

    08/31/2001 14:34:56 1

    13/01/2001 14:34:56 0

    0a/31/2001 14:34:56 0

    08/32/2001 14:34:56 0

    21/31/2001 14:34:56 0

    (10 row(s) affected)

    That would allow 30th February as a valid date. . . In fact, it'd allow 39th February 😉


    Forever trying to learn
    My blog - http://www.cadavre.co.uk/
    For better, quicker answers on T-SQL questions, click on the following...http://www.sqlservercentral.com/articles/Best+Practices/61537/
    For better, quicker answers on SQL Server performance related questions, click on the following...http://www.sqlservercentral.com/articles/SQLServerCentral/66909/

  • Cadavre (9/30/2011)


    Michael Valentine Jones (9/30/2011)


    Here is a fairly simple check that will work with any setting of DATEFIRST:

    select

    a.dt,

    IsValidDateTime =

    case

    -- Check that date string is in correct format, mm/dd/yyyy hh:mm:ss

    when dt not like '[0-1][0-9]/[0-3][0-9]/[1-9][0-9][0-9][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9]'

    then 0

    -- Reformat and test date in universal format of yyyymmdd hh:mm:ss

    when isdate(substring(a.dt,7,4)+substring(a.dt,1,2)+substring(a.dt,4,2)+substring(a.dt,11,9)) <> 1

    then 0

    else 1

    end

    from

    ( -- Test Data

    select dt = '08/31/2001 14:34:56'union all

    select dt = '08/31/2001 34:34:56'union all

    select dt = '08/31/2001 14:64:56'union all

    select dt = '08/31/2001 14:34:66'union all

    select dt = '08/31/2001 25:34:56'union all

    select dt = '08/31/2001 14:34:56'union all

    select dt = '13/01/2001 14:34:56'union all

    select dt = '0a/31/2001 14:34:56'union all

    select dt = '08/32/2001 14:34:56'union all

    select dt = '21/31/2001 14:34:56'

    ) a

    Results:

    dt IsValidDateTime

    ------------------- ---------------

    08/31/2001 14:34:56 1

    08/31/2001 34:34:56 0

    08/31/2001 14:64:56 0

    08/31/2001 14:34:66 0

    08/31/2001 25:34:56 0

    08/31/2001 14:34:56 1

    13/01/2001 14:34:56 0

    0a/31/2001 14:34:56 0

    08/32/2001 14:34:56 0

    21/31/2001 14:34:56 0

    (10 row(s) affected)

    That would allow 30th February as a valid date. . . In fact, it'd allow 39th February 😉

    No it wouldn't. You could have tested that before you posted. 😉

  • Michael Valentine Jones (9/30/2011)


    No it wouldn't. You could have tested that before you posted. 😉

    Yep, or I should've just read the query properly! Didn't see the part of the case statement where you used the ISDATE function on the formatted date. Sorry 🙂


    Forever trying to learn
    My blog - http://www.cadavre.co.uk/
    For better, quicker answers on T-SQL questions, click on the following...http://www.sqlservercentral.com/articles/Best+Practices/61537/
    For better, quicker answers on SQL Server performance related questions, click on the following...http://www.sqlservercentral.com/articles/SQLServerCentral/66909/

Viewing 15 posts - 1 through 14 (of 14 total)

You must be logged in to reply to this topic. Login to reply