September 21, 2011 at 8:05 am
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!
September 21, 2011 at 3:18 pm
September 22, 2011 at 2:48 am
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?
September 22, 2011 at 9:18 am
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 🙂
September 23, 2011 at 9:07 am
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
September 27, 2011 at 8:58 am
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.
September 27, 2011 at 10:53 am
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
September 29, 2011 at 8:49 am
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.
September 30, 2011 at 8:55 am
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
September 30, 2011 at 9:35 am
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})?$)
September 30, 2011 at 10:26 am
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
September 30, 2011 at 10:57 am
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)
September 30, 2011 at 11:02 am
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 😉
September 30, 2011 at 12:24 pm
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. 😉
September 30, 2011 at 1:02 pm
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 🙂
Viewing 15 posts - 1 through 14 (of 14 total)
You must be logged in to reply to this topic. Login to reply