0

I have a RegEx that validates a date coming in. What I want it to allow:

MM/dd/YYYY M/d/YYYY MM-dd-YYYY M-d-YYYY MM.dd.YYYY M.d.YYYY MMddYYYY

And a few other variants.

Here's my expression:

^((0[1-9]|1[012])[- /.]?(0[1-9]|[12][0-9]|3[01])[- /.]?(19|20)\d\d)|((((0?[13578])|(1[02]))[- /.]?((0?[1-9])|([12][0-9])|(3[01]))|((0?[469])|(11))[- /.]?((0?[1-9])|([12][0-9])|(30))|(0?[2])[- /.]?((0?[1-9])|([1][0-9])|([2][0-8])))[- /.]?(19\d{2}|20\d{2}))|(((0?[2]))[- /.]?((0?[1-9])|([12][0-9]))[- /.]?((19|20)(04|08|[2468][048]|[13579][26])|2000))$

I'm getting the majority to work, but the dates that I do not want to work is MdYYYY, MMdYYYY, or MddYYYY

I want the RegEx to be the only thing changed because it's being called in multiple spots for the same reason, limiting the amount of code I need to adjust.

I'm calling this RegEx from this Case statement which is in my custom TextBoxPlus.ascx:

Case TextBoxPlusType.DateOnlyMMDDYYYY
WatermarkText = "mmddyyyy"
ValidationExpression = "^((0[1-9]|1[012])[- /.]?(0[1-9]|[12][0-9]|3[01])[- /.]?(19|20)\d\d)|((((0?[13578])|(1[02]))[- /.]?((0?[1-9])|([12][0-9])|(3[01]))|((0?[469])|(11))[- /.]?((0?[1-9])|([12][0-9])|(30))|(0?[2])[- /.]?((0?[1-9])|([1][0-9])|([2][0-8])))[- /.]?(19\d{2}|20\d{2}))|(((0?[2]))[- /.]?((0?[1-9])|([12][0-9]))[- /.]?((19|20)(04|08|[2468][048]|[13579][26])|2000))$"
ErrorMessage = "Please enter a valid date format<br><b>mm/dd/yyyy<br>mmddyyyy</b>"

This is on the actual aspx.vb page calling TextBoxPlus (my custom control):

If (Not (Date.TryParseExact(IssueDate.Text, "MMddyyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, Globalization.DateTimeStyles.None, New Date))) Then
If (Not (Date.TryParseExact(IssueDate.Text, "MM/dd/yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, Globalization.DateTimeStyles.None, New Date))) Then
    showIfBadDate.Visible = True
    BadDate_AM.Show()
Else
IssueDate_ = Date.ParseExact(IssueDate.Text, "MM/dd/yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo)
End If
Else
IssueDate_ = Date.ParseExact(IssueDate.Text, "MMddyyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo)
End If
Kevin Fischer
  • 371
  • 7
  • 16
  • Yikes, I would split each one up into a separate regex, and then put all the validation code in its own method/function somewhere. – 4castle Jan 03 '17 at 19:06
  • 4
    That regex is ridiculous. If I had to maintain that, I'd track you down and kick you in the head. It's better to standardize. Pick the *one* format you want, and then manipulate the user's input into that format. Validation isn't even the only concern here. Having to present all these different date formats in any reasonable way will be a whole other maintenance nightmare. – Chris Pratt Jan 03 '17 at 19:08
  • funny story, this is old regex that I'm trying to clean up – Kevin Fischer Jan 03 '17 at 19:09
  • i'm going to update my question, maybe that will help a bit – Kevin Fischer Jan 03 '17 at 19:10
  • 1
    What language is the regex being run in? It is possible that there are better methods available, for example in .NET you could use [DateTime.TryParseExact](https://msdn.microsoft.com/en-us/library/h9b85w22(v=vs.110).aspx) and give it an array of acceptable date formats. – Andrew Morton Jan 03 '17 at 19:12
  • I guess a good question can be, can I have more than one expression in the ValidationExpression? – Kevin Fischer Jan 03 '17 at 19:12
  • It's in VB.net and I am using Date.TryParseExact() – Kevin Fischer Jan 03 '17 at 19:13
  • Note that `DataTime.TryParseExact` accepts an array of formats so you cant test input against all of them in one call – Ňɏssa Pøngjǣrdenlarp Jan 03 '17 at 19:56
  • I was thinking about using that, but being the fact i was to use this code on multiple pages, i'm trying to get as much on the custom textbox validation as I can – Kevin Fischer Jan 03 '17 at 19:57
  • 1
    You should make it clearer you are using that Plus control. Its a more salient tidbit than VS2010 or Date – Ňɏssa Pøngjǣrdenlarp Jan 03 '17 at 20:49
  • Can do. will adjust – Kevin Fischer Jan 03 '17 at 20:51

1 Answers1

4

If you're using it in a few places, it would be best to use a function to determine the validity of the strings as dates in the acceptable formats:

Option Infer On
Option Strict On

Imports System.Globalization

Module Module1

    Function IsValidDate(s As String) As Boolean
        Dim validFormats = {"MM/dd/yyyy", "M/d/yyyy", "MM-dd-yyyy", "M-d-yyyy", "MM.dd.yyyy", "M.d.yyyy", "MMddyyyy"}
        Dim dt As DateTime
        Dim ci As New CultureInfo("en-US")

        Return DateTime.TryParseExact(s, validFormats, ci, DateTimeStyles.None, dt)

    End Function

    Sub Main()
        Dim stringsToTry = {"01/31/2016", "1/31/2016", "01-31-2016", "1-9-2016", "01.31.2016", "1.9.2016", "01312016", "112016", "1212016", "1122016"}

        For Each s In stringsToTry
            Console.WriteLine("{0,-10}: {1}", s, IsValidDate(s))
        Next

        Console.ReadLine()

    End Sub

End Module

Outputs:

01/31/2016: True
1/31/2016 : True
01-31-2016: True
1-9-2016  : True
01.31.2016: True
1.9.2016  : True
01312016  : True
112016    : False
1212016   : False
1122016   : False

With a small change, you could get the function to return a Nullable(Of DateTime) if it is desirable to get the parsed date if it exists.

Andrew Morton
  • 24,203
  • 9
  • 60
  • 84
  • I'm actually doing something similar to that. i'll update my question – Kevin Fischer Jan 03 '17 at 19:46
  • @KevinFischer Are you saying that the validation expression needs to work in JavaScript? If so, I suggest that you use a really simple regex for that and leave the actual check to the code-behind on the server. – Andrew Morton Jan 03 '17 at 19:58
  • I'm not using any JS. – Kevin Fischer Jan 03 '17 at 20:00
  • @KevinFischer In that case, I cannot see why you would need a regex - you haven't explained its use in preference to a simple method which works. – Andrew Morton Jan 03 '17 at 20:02
  • It creates an error message, which produces a popup message It uses an ajaxToolkit:ValidatorCalloutExtender and asp:RegularExpressionValidator – Kevin Fischer Jan 03 '17 at 20:06
  • @KevinFischer Those use JavaScript on the rendered page. I suggest a regex like `^[0-9]{1,2}[-/.]?[0-9]{1,2}[-/.]?[0-9]{4}$` for a simple check and rely on the code-behind for the thorough check. – Andrew Morton Jan 03 '17 at 20:14
  • I tried that but it won't produce my error message because it allows MdYYYY, or variations of that. – Kevin Fischer Jan 03 '17 at 20:15
  • 1
    @KevinFischer It looks like a CustomValidator would be better for you: [Date validation with ASP.NET validator](http://stackoverflow.com/a/939960/1115360). – Andrew Morton Jan 03 '17 at 20:22