10

I use asp.net 4 and c#.

I need to use a WebControl of type Validation namely RegularExpressionValidator to detect data inputed in a TextBox that IS NOT in format yyyy-MM-dd (String).

Any idea how to write the RegEx to apply ot this control?

Thanks

GibboK
  • 71,848
  • 143
  • 435
  • 658
  • 4
    *You have a problem and decide to solve it by using a regular expression.... now you have two....* – marc_s Mar 09 '11 at 14:41
  • 2
    Regular Expression is good for the format, but validating it is an actual date is extremely hard in regex (How do you handle leap years, etc?) - you didn't specify if you needed that. If it is, you're best bet is to create a CustomValidator, and use `Date.parse` (Returns NaN if not a DateTime) client side to test for failure, and `DateTime.TryParse` server side. – vcsjones Mar 09 '11 at 14:43

7 Answers7

17

Here's one possible regex:

^\d{4}-((0\d)|(1[012]))-(([012]\d)|3[01])$

Note: this will prevent months >12 and days >31, but won't check specific months for length (ie it won't block 30th Feb or 31st Apr). You could write a regex to do that, but it would be quite lengthy, and 29th Feb is always going to give you problems in regex.

I'd say if you need that kind of fine-grained validation, you're better off parsing the date with a date library; regex isn't the tool for you. This regex should be sufficient for basic pre-validation though.

I've also gone lenient on the year; just checking that it's four digits. But if you want some sort of sanity check (ie within certain bounds), it shouldn't be too hard to add. Foe example, if you want to match only dates in the this century, you would replace the \d{4} at the beginning of the regex with 20\d{2}. Again, trying to validate a date with excessive accuracy in regex is going to be difficult and you should use a date parser, but you can get basic century-level matching quite easily to prevent the user entering anything really silly.

Finally, I've put ^ and $ to tie off the ends of the string so it can't match if the user enters a valid date and extra characters as well. (You may want to add a string length validator for this as well).

Hope that helps.

Spudley
  • 166,037
  • 39
  • 233
  • 307
10

Spudley's answer above allows 00 for day and month.

I fixed it :

^\d{4}-((0[1-9])|(1[012]))-((0[1-9]|[12]\d)|3[01])$

Note: neither of these expressions check for days in a month that are invalid, e.g. 04/31, 06/31 or 02/29 on non-leap years.

Ralph177
  • 201
  • 3
  • 5
5

Regular expression \d\d\d\d-\d\d-\d\d should do the trick.

Goran Jovic
  • 9,418
  • 3
  • 43
  • 75
redent84
  • 18,901
  • 4
  • 62
  • 85
  • 1
    @Daniel the original poster doesn't seem interested in whether the date is invalid. – robert Mar 09 '11 at 14:38
  • sure he does, he talked about the format `yyyy-MM-dd` which implies that the string is a valid date. – Daniel Hilgarth Mar 09 '11 at 14:39
  • 5
    @Daniel Provide one that doesn't allow invalid dates instead of down voting. – rick schott Mar 09 '11 at 14:41
  • 1
    Is it even possible to check the validity of a date using nothing but regular expressions? What about leap years? – Kristof Claes Mar 09 '11 at 14:42
  • @rick schott: I think you didn't understand what downvoting is for: It is a tool to flag wrong answers. Besides, Brent Worden already posted a link to correct ones. – Daniel Hilgarth Mar 09 '11 at 14:43
  • @Kristof Claes - no, it isn't possible. Or... well, I guess it's *possible*, but not sensibly feasible. As you say, Feb 29th will always be the kicker. – Spudley Mar 09 '11 at 14:45
  • 1
    @Kristof @Spudley it is possible as I have done it using various regexs found on the Regular Expression Library. A lot of them take into account leap days. – Brent Worden Mar 09 '11 at 14:48
  • Even than your answer is wrong, because all valid dates are a subset of your regex. – Daniel Hilgarth Mar 09 '11 at 14:51
  • Maybe, there's a **better** solution, but that doesn't mean that mine is _wrong_ . Obviously Spudley's solution is more complete, but it's not perfect, and of course it's not _wrong_ – redent84 Mar 09 '11 at 14:55
  • Well, that's a matter of perspective, I guess. – Daniel Hilgarth Mar 09 '11 at 14:56
3

I would like to add a little change in Spudley's answer:

^\d{4}$|^\d{4}-((0?\d)|(1[012]))-(((0?|[12])\d)|3[01])$

so you can use date like 2013-5-5 (month and date is not necessary the zero but can be used)

Hope it helps.

Simba
  • 4,952
  • 3
  • 19
  • 29
Mr Z
  • 101
  • 1
  • 5
  • You are right, but this also allows the year 0000 that never exists, the count starts in year 1 AD, and the year before is 1 BC (the zero was not conceptualized at that time), this is why the millennium starts on 2001 and not in 2000 as many people celebrates it. – TrustworthySystems May 13 '21 at 04:36
0

Another implementation for ISO 8601 structured dates:

^\d{4}-\d{1,2}-\d{1,2}\s\d{1,2}:\d{1,2}:\d{1,2}.?\d{0,}$

It's not quite as strict, and will accept incorrect dates, but it should validate that it follows the ISO 8601 structure even if the date is a non-existent one. It should also be fairly simple to understand for anyone with a basic Regex understanding.

If you really want to ensure the date is correct, and work with it, run DateTime.TryParse() on it.

gpresland
  • 1,690
  • 2
  • 20
  • 31
0
(19|20)[0-9]{2}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])

mach result:

1999-09-12

-1
((([0-9][0-9][0-9][1-9])|([1-9][0-9][0-9][0-9])|([0-9][1-9][0-9][0-9])|([0-9][0-9][1-9][0-9]))-((0[13578])|(1[02]))-((0[1-9])|([12][0-9])|(3[01])))|((([0-9][0-9][0-9][1-9])|([1-9][0-9][0-9][0-9])|([0-9][1-9][0-9][0-9])|([0-9][0-9][1-9][0-9]))-((0[469])|11)-((0[1-9])|([12][0-9])|(30)))|(((000[48])|([0-9]0-9)|([0-9][1-9][02468][048])|([1-9][0-9][02468][048]))-02-((0[1-9])|([12][0-9])))|((([0-9][0-9][0-9][1-9])|([1-9][0-9][0-9][0-9])|([0-9][1-9][0-9][0-9])|([0-9][0-9][1-9][0-9]))-02-((0[1-9])|([1][0-9])|([2][0-8])))

This is the regex for yyyy-MM-dd format.

You can replace - with \/ for yyyy/MM/dd...

Tested working perfect..

falsarella
  • 12,217
  • 9
  • 69
  • 115
Ajit
  • 1