• poeorlco (unregistered)

    -insert jwz regexp quote here-

  • Annon (unregistered)

    frist (this is not spam)

  • KattMan (cs)

    So what is wrong with trying a DateTime.TryParse and letting it either set a proper date for you or return false if it isn't valid? I actually think there is a problem with some people using regex for everything when it isn't needed. It's a tool with certian uses, it is not a swiss army knife for everything. Why re-invent the wheel?

  • snoofle (cs)
    Alex:
    new Regex(@"^((0?[1-9]|[12][1-9]|3[01])\.(0?[13578]|1[02])\.20[0-9]{2}|(0?[1-9]|[12][1-9]|30)\.(0?[13456789]|1[012])\.20[0-9]{2}|(0?[1-9]|1[1-9]|2[0-8])\.(0?[123456789]|1[012])\.20[0-9]{2}|(0?[1-9]|[12][1-9])\.(0?[123456789]|1[012])\.20(00|04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96))$")

    That seems reasonable. As we've often pointed out, doing date validation is hard, so it makes sense that anyone doing date validation would use a hard RE!

  • MSNetExpert (unregistered)

    The reality of it is, DateTime.TryParse uses the exact same Regex internally ... This smart Joe has actually optimized the code by removing one useless function call to TryParse

  • snoofle (cs) in reply to KattMan
    KattMan:
    So what is wrong with trying a DateTime.TryParse and letting it either set a proper date for you or return false if it isn't valid? I actually think there is a problem with some people using regex for everything when it isn't needed. It's a tool with certian uses, it is not a swiss army knife for everything. Why re-invent the wheel?
    I can't speak for other languages, but in java, you can do: new SimpleDateFormat("yyyyMMdd").parse("20121143") and get Dec 13, 2012, which doesn't exactly let you know that the input was in/valid.
  • KattMan (cs) in reply to MSNetExpert
    MSNetExpert:
    The reality of it is, DateTime.TryParse uses the exact same Regex internally ... This smart Joe has actually optimized the code by removing one useless function call to TryParse

    Maybe, how do you know he didn't add a bug with a transposition of two characters, or missing a key stroke, or changing a charater somewhere in there? If he did any of these, debugging it would be a pain.

  • KattMan (cs) in reply to snoofle
    snoofle:
    KattMan:
    So what is wrong with trying a DateTime.TryParse and letting it either set a proper date for you or return false if it isn't valid? I actually think there is a problem with some people using regex for everything when it isn't needed. It's a tool with certian uses, it is not a swiss army knife for everything. Why re-invent the wheel?
    I can't speak for other languages, but in java, you can do: new SimpleDateFormat("yyyyMMdd").parse("20121143") and get Dec 13, 2012, which doesn't exactly let you know that the input was in/valid.
    This is true, but proper usage of input controls can help with this. If it is a flat file read, might need to take a different route, I'll admit that.
  • Nick V (unregistered)

    I do not see what the issue is, here. If you are doing client-side validation, which is always a good idea, using a regex to validate your date (by the way: this is a good regex to validate a date) is not a bad idea at all.

    Of course, in 2012: JQuery, Telerik, etc...

    I apologize but WTF this ain't.

  • da Doctah (cs)

    I heard from someone at Apple that Siri is actually just one great big regex.

  • Rajendra Kumar (unregistered)

    Dearest Pros, I am needing of program just like this. Only it should be having ANSI C99 codes. I am team leader at major South Asian company and it is important this be delivered to my direct reports. That way I can get back to drinking chai and smoking fags. Plz send to Rajkum@gmail.biz, it's URGENT!

  • ThingGuy McGuyThing (cs)

    I really get the impression that this bit is supposed to detect leap-years:

    20(00|04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96)

    ...but I can't for the life of me find a corresponding 02/29 type of sequence.

  • Nagesh (cs)

    This is clear work of politics in project. This person is trying to get project bonus for maximum length of stay in project. So writing of unmentionable code is one way of making this achieving goal.

    I salute this person's wise-dome.

  • frits (cs) in reply to da Doctah
    da Doctah:
    I heard from someone at Apple that Siri is actually just one great big regex.
    Actually, I heard she's Thetan Level VI already (same thing really).
  • Ani Moose (unregistered) in reply to KattMan
    KattMan:
    MSNetExpert:
    The reality of it is, DateTime.TryParse uses the exact same Regex internally ... This smart Joe has actually optimized the code by removing one useless function call to TryParse

    Maybe, how do you know he didn't add a bug with a transposition of two characters, or missing a key stroke, or changing a charater somewhere in there? If he did any of these, debugging it would be a pain.

    Oh... like the missing 10th and 20th days of the month? Regex(@"^((0?[1-9]|[12][1-9]|3[01])

  • Ani Moose (unregistered) in reply to ThingGuy McGuyThing
    ThingGuy McGuyThing:
    I really get the impression that this bit is supposed to detect leap-years:

    20(00|04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96)

    ...but I can't for the life of me find a corresponding 02/29 type of sequence.

    It's here: (0?[1-9]|[12][1-9]).(0?[123456789]|1[012]).20(00|04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96)

    You just can't have a Feb 10th or Feb 20th.

  • Maltz (unregistered) in reply to ThingGuy McGuyThing
    ThingGuy McGuyThing:
    I really get the impression that this bit is supposed to detect leap-years:

    20(00|04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96)

    ...but I can't for the life of me find a corresponding 02/29 type of sequence.

    Beyond that, it's still wrong. 1900 wasn't a leap year.

    Leap years are every 4 years... except every 100... except every 400. So 1700, 1800, 1900 are not leap years, 1600, 2000, and 2400 are.

  • Dude (unregistered) in reply to Ani Moose

    It gets a bit more weird than that, due to redundancy caused by how February is checked, you can have a 20th of any month, and a 10th of any month in year % 4 == 0 (note that this is not correct for detecting leap years you also need year % 400 != 0)

  • Dude (unregistered) in reply to Dude

    And reading the comment above mine, I see that I was wrong about the century rule as well. Just more reason why you should let the date library handle it.

  • Rick (cs) in reply to snoofle
    snoofle:
    KattMan:
    So what is wrong with trying a DateTime.TryParse and letting it either set a proper date for you or return false if it isn't valid? I actually think there is a problem with some people using regex for everything when it isn't needed. It's a tool with certian uses, it is not a swiss army knife for everything. Why re-invent the wheel?
    I can't speak for other languages, but in java, you can do: new SimpleDateFormat("yyyyMMdd").parse("20121143") and get Dec 13, 2012, which doesn't exactly let you know that the input was in/valid.
    Granted the default is wrong, but applying setLenient(false) to a SimpleDateFormat object is not all that hard.
  • HP PhaserJet (unregistered) in reply to da Doctah
    da Doctah:
    I heard from someone at Apple that Siri is actually just one great big regex.
    The offspring of Com Truise and Hatie Kolem's is's a giant dinosuar with tiny arms (what a cruel twist of fate) and what a twisted cruel fatty are you!
  • KattMan (cs) in reply to Rick

    Ok, here's how I would probably handle it just to cover my own butt.

    Let regex do what it does best, validate the PATTERN matches one of the following: "99/99/9999", "99-99-9999", "9999/99/99" or "9999-99-99", this is easy and accounts for day, month or year first. This lets me know it is the form I require, then use date functions to validate that it is a proper date according to current localization. No more missing days and bad leap years and the regex makes sure the pattern is correct.

  • greyfade (unregistered)

    I made a better one:

    /^(((0?[13578]|1[02])\/([0-2]?[1-9]|[123]0|31)|(0?[469]|11)\/([0-2]?[1-9]|[123]0)|0?2\/([0-1]?[1-9]|[12]0|2[1-8]))\/(19|20)?[0-9]{2}|0?2\/29\/((20)?00|(19|20)?([02468][48]|[13579][26]|[2468]0)))$/

    It's not only a lot shorter, but it's easier to read, and correctly matches all dates from 1/1/1900 to 12/31/2099, with no false positive. :)

  • Yoh (unregistered)

    Sorry but your "easier to read" regex is still a pain in the ass to read.

    And what happens when the requirements for the input changes? I mean, there are a ton of different ways to specify a date.

    This is really not a very scalable solution, and therefore not an appropriate tool in my opinion.

  • Zylon (cs) in reply to Annon
    Annon:
    frist (this is not spam)
    Wrong on both counts.
  • Sam I am (unregistered)

    "(1[0-2]|0?[1-9])/(3[0-1]|[1-2][0-9]|0?[1-9])/[0-9][0-9][0-9][0-9]"

  • LANMind (unregistered) in reply to KattMan
    KattMan:
    MSNetExpert:
    The reality of it is, DateTime.TryParse uses the exact same Regex internally ... This smart Joe has actually optimized the code by removing one useless function call to TryParse

    Maybe, how do you know he didn't add a bug with a transposition of two characters, or missing a key stroke, or changing a charater somewhere in there? If he did any of these, debugging it would be a pain.

    You have difficulty recognizing sarcasm, don't you?

  • The Mr. T Experience (unregistered) in reply to Zylon
    Zylon:
    Annon:
    frist (this is not spam)
    Wrong on both counts.
    Wow. Your so inciteful.
  • Jay (unregistered)

    This demonstrates both the power of RegExes -- a fairly complex validation done in just 3 or 4 lines of code -- and their danger -- it's very difficult to comprehend, so the error about the 10th and 20th of the month being illegal slipped through.

    I suppose in this case maintainability isn't a big issue. It's unlikely that the numbers of days in a month will change any time soon.

    Though curiously, this validation only accepts dates in the 21st century. That's fine if the dates are all going to be in the recent past or near future, like order date and shipping date of new orders. But it will reject the birth date of anyone over 12 years old, not to mention any dates on other records that go back that far.

  • greyfade (unregistered) in reply to Yoh

    My regex is used in a system whose data formats are specified by a handful of US government standards. Those standards rarely, if ever, change such minutiae. Neither I nor any of my coworkers were concerned about needing to change it.

    It was both the appropriate tool in my case, and the only feasible option at the time.

  • Yoshord (unregistered) in reply to Maltz
    Maltz:
    ThingGuy McGuyThing:
    I really get the impression that this bit is supposed to detect leap-years:

    20(00|04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96)

    ...but I can't for the life of me find a corresponding 02/29 type of sequence.

    Beyond that, it's still wrong. 1900 wasn't a leap year.

    Leap years are every 4 years... except every 100... except every 400. So 1700, 1800, 1900 are not leap years, 1600, 2000, and 2400 are.

    This regex doesn't think 1900 is a leap year; it doesn't match 2100 or 1800 either, so I don't know why you felt the need to bring up the fact that those aren't leap years.

  • big picture thinker (unregistered)

    Don't know why the entire validation is regex. You could use it for parts, but I think it would be better to split the year, month, and date parts and then perform some procedural logic on those parts.

  • taixzo (cs) in reply to Yoshord
    Yoshord:
    Maltz:
    ThingGuy McGuyThing:
    I really get the impression that this bit is supposed to detect leap-years:

    20(00|04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96)

    ...but I can't for the life of me find a corresponding 02/29 type of sequence.

    Beyond that, it's still wrong. 1900 wasn't a leap year.

    Leap years are every 4 years... except every 100... except every 400. So 1700, 1800, 1900 are not leap years, 1600, 2000, and 2400 are.

    This regex doesn't think 1900 is a leap year; it doesn't match 2100 or 1800 either, so I don't know why you felt the need to bring up the fact that those aren't leap years.

    The regex doesn't think 1900 is anything. Look at the start of that sequence: it starts with 20. So it will only accept years from 2000 to 2099, inclusive.

  • qbolec (unregistered)

    I think we need a library, that allows us to describe regular languages using productions, and at compile time compiles it to regexp (or even to automata).

    I mean something like:

    const DateRegExp = RegExp{
      UsualDay >= [1-9]|1\d|2[0-8],
      Month >= [1-9]|1[0-2],
      Year >= \d+,
      LongDay >= 29|30,
      LongMonth >= [13-9]|1[0-2],
      LongerDay >= 31,
      LongerMonth >= [13578]|1[02],
      OtherYearDate >= LongerDay.LongerMonth.Year | LongDay.LongMonth.Year,
      OtherYearDate >= UsualDay.Month.Year,
      DivisibleBy4 >= (\d*([02468][048]|[13579][26])) and not 0.+,
      DivisibleBy100 >= \d*00 and not 0.+,
      DivislbleBy400 >= (DivisbleBy4)00 and not 0.+,
      LeapYear >= DivisibleBy400 or (DivisibleBy4 and not DivisibleBy100),
      LeapYearBonus >= 29.02.LeapYear,
      Date >= LeapYearBonus | OtherYearDate,
    };
    

    You may notice that my notation of gramar resembles context free grammar, but is actually regular, as I only use non-terminals defined previously. I also want to use negation and intersection, which still keeps me inside regular languages.

    Do you know a language+compiler that supports somthing like that?

  • Neil (unregistered)

    I was almost incited to reply to The Mr. T Experience.

  • Not sure if Fry or just Philip (unregistered) in reply to qbolec
    qbolec:
    I think we need a library, that allows us to describe regular languages using productions, and at compile time compiles it to regexp (or even to automata).

    I mean something like:

    const DateRegExp = RegExp{
      UsualDay >= [1-9]|1\d|2[0-8],
      Month >= [1-9]|1[0-2],
      Year >= \d+,
      LongDay >= 29|30,
      LongMonth >= [13-9]|1[0-2],
      LongerDay >= 31,
      LongerMonth >= [13578]|1[02],
      OtherYearDate >= LongerDay.LongerMonth.Year | LongDay.LongMonth.Year,
      OtherYearDate >= UsualDay.Month.Year,
      DivisibleBy4 >= (\d*([02468][048]|[13579][26])) and not 0.+,
      DivisibleBy100 >= \d*00 and not 0.+,
      DivislbleBy400 >= (DivisbleBy4)00 and not 0.+,
      LeapYear >= DivisibleBy400 or (DivisibleBy4 and not DivisibleBy100),
      LeapYearBonus >= 29.02.LeapYear,
      Date >= LeapYearBonus | OtherYearDate,
    };
    

    You may notice that my notation of gramar resembles context free grammar, but is actually regular, as I only use non-terminals defined previously. I also want to use negation and intersection, which still keeps me inside regular languages.

    Do you know a language+compiler that supports somthing like that?

    Yup. All of them. Instead of a snappy one-liner, split the regex into several commented parts. Pros: you don't have to learn a whole new language, you use regex. Cons: you still have to use regex.

  • Jerry (unregistered) in reply to MSNetExpert
    MSNetExpert:
    The reality of it is, DateTime.TryParse uses the exact same Regex internally ... This smart Joe has actually optimized the code by removing one useless function call to TryParse
    What's more, libraries can change out from under you, introducing hard-to-debug new behaviors in your app.

    Far better to write your own stable code. Then you know it will work, now and forever.

  • Timm (unregistered) in reply to qbolec
    qbolec:
    Do you know a language+compiler that supports somthing like that?
    I don't use it myself, but from what I hear, emacs can do anything.
  • sdhfs (unregistered) in reply to Maltz
    Maltz:
    ThingGuy McGuyThing:
    I really get the impression that this bit is supposed to detect leap-years:

    20(00|04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96)

    ...but I can't for the life of me find a corresponding 02/29 type of sequence.

    Beyond that, it's still wrong. 1900 wasn't a leap year.

    Leap years are every 4 years... except every 100... except every 400. So 1700, 1800, 1900 are not leap years, 1600, 2000, and 2400 are.

    Too lazy to have a look at how many people have already said this....

    how is 1900 in there?

  • Titor (unregistered) in reply to taixzo
    taixzo:
    Yoshord:
    Maltz:
    ThingGuy McGuyThing:
    I really get the impression that this bit is supposed to detect leap-years:

    20(00|04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96)

    ...but I can't for the life of me find a corresponding 02/29 type of sequence.

    Beyond that, it's still wrong. 1900 wasn't a leap year.

    Leap years are every 4 years... except every 100... except every 400. So 1700, 1800, 1900 are not leap years, 1600, 2000, and 2400 are.

    This regex doesn't think 1900 is a leap year; it doesn't match 2100 or 1800 either, so I don't know why you felt the need to bring up the fact that those aren't leap years.

    The regex doesn't think 1900 is anything. Look at the start of that sequence: it starts with 20. So it will only accept years from 2000 to 2099, inclusive.

    We didn't have Leap years in the 20th Century, and you might be interested to hear they get rid of them before the 22nd....

  • RandomGuy (unregistered) in reply to Ani Moose
    Ani Moose:
    ThingGuy McGuyThing:
    I really get the impression that this bit is supposed to detect leap-years:

    20(00|04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96)

    ...but I can't for the life of me find a corresponding 02/29 type of sequence.

    It's here: (0?[1-9]|[12][1-9]).(0?[123456789]|1[012]).20(00|04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96)

    You just can't have a Feb 10th or Feb 20th.

    That's here: (0?[1-9]|1[1-9]|2[0-8]).(0?[123456789]|1[012]).20[0-9]{2}

    Actually, the Feb 29th part could have been reduced to (29).(0?2).20([02468][048]|[13579][26])

    I'd rather criticize the very limited time period this code is valid -- but who knows, if earth still exists in 2100 ...

  • Oblig (unregistered)

    You have a problem.

    You decide to use a regex.

    Now you have 00|04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96 problems.

  • barf4eva (unregistered) in reply to Jerry
    Jerry:
    MSNetExpert:
    The reality of it is, DateTime.TryParse uses the exact same Regex internally ... This smart Joe has actually optimized the code by removing one useless function call to TryParse
    What's more, libraries can change out from under you, introducing hard-to-debug new behaviors in your app.

    Far better to write your own stable code. Then you know it will work, now and forever.

    OK, now I'm not sure if you guys are still being sarcastic or not.

    And it is scaring me!

  • Dave (unregistered)

    TRWTF is having a national date format that puts Months first.

    Day Month Year has a logic to it, but is ordered the wrong way round for sorting.

    Year Month Day makes complete sense, and is sortable, (so long as the year is 4 digits - don't forget Y2K compliance!)

    But Month Day Year has neither logic nor sortability.

  • Sutherlands (cs)

    GAH! This is SO horrible! Doesn't he know that you should store the regex for repeat use, since the most expensive part is creating it? sigh

  • LOADING (unregistered) in reply to KattMan
    KattMan:
    So what is wrong with trying a DateTime.TryParse and letting it either set a proper date for you or return false if it isn't valid? I actually think there is a problem with some people using regex for everything when it isn't needed. It's a tool with certian uses, it is not a swiss army knife for everything. Why re-invent the wheel?

    "Reinventing the wheel" is inappropriate here. This is a phrase easier said than justified. A full datetime implementation is a series of wheels, if you want to compare it to a clock or the orbital characteristics of the planet Earth.

    The wheel is simple and works, accurate date validation and handling is a complex process. You can get away with reinventing the wheel. You can do so with out doing anything too complex. You can make a derivative for another purpose or type of terrain, indeed, the mechanical and industrial ages were brought about by a few simple reinventions of the wheel and the subsequent application of the inventions.

    I can forgive someone for remaking there own version of something simple, or an alternative version. But when it comes to more complex things that are already done for you, you can't get away with it, use a library that is reasonably accurate and has been heavily debugged.

  • Tom (unregistered) in reply to ThingGuy McGuyThing
    ThingGuy McGuyThing:
    I really get the impression that this bit is supposed to detect leap-years:

    20(00|04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96)

    ...but I can't for the life of me find a corresponding 02/29 type of sequence.

    TRWTF is that you looked that closely.

  • The Mr. T Experience (unregistered) in reply to Neil
    Neil:
    I was almost incited to reply to The Mr. T Experience.
    ;D
  • Kuba (cs) in reply to KattMan
    KattMan:
    MSNetExpert:
    The reality of it is, DateTime.TryParse uses the exact same Regex internally ... This smart Joe has actually optimized the code by removing one useless function call to TryParse

    Maybe, how do you know he didn't add a bug with a transposition of two characters, or missing a key stroke, or changing a charater somewhere in there? If he did any of these, debugging it would be a pain.

    Obviously, you have a test harness for that regex, right? RIGHT?

  • default_ex (unregistered)

    That's some ugly regex for validating a date, even considering it invalidates (some) leap years. But then I've recently written several hundred lines of regex to parse a C-like language (without trimming comments), probably don't deserve the right to call a single line of regex ugly.

Leave a comment on “Simple Date Validation”

Log In or post as a guest

Replying to comment #:

« Return to Article