10

The regex should match valid dates in a string in the format YYYYMMDD. For example, aaa_20150327_bbb should be matched but aaa_20150229_bbb not because 2015 is not a leap year.

Only year from 2000 to 2099 need to be considered.

enrico.bacis
  • 27,413
  • 7
  • 76
  • 108
Joe Wang
  • 109
  • 1
  • 1
  • 3
  • 5
    It's not going to be possible to exclude `2/29` if it's not a leap year with regex. At least not in a sane way. You'll have to parse that out after the fact. Is there a problem with `\d{8}` ? Or at least `20\d{2}[01]\d[0123]\d`? – Adam Smith Mar 27 '15 at 18:34
  • @JoeWang What language are you using? C++ has the functionality to do this built-in, without the use of a regex – Jonathan Mee Mar 27 '15 at 18:37
  • ahh... how re can achieve this... just do 5 min research about what re is will let you be able to rule this possibility out. – Jason Hu Mar 27 '15 at 18:39
  • 2
    This is not an appropriate problem for RegEx. Fortunately there are good libraries for dealing with dates. Extract the string and then use a date parsing library to work with it as a date. – Coenwulf Mar 27 '15 at 18:44
  • Have a look at: http://stackoverflow.com/a/3873172/372239 – Toto Mar 27 '15 at 20:24

2 Answers2

19

Total madness (years 0-9999)

The following one (based on this answer) works for years between 0 and 9999.

(?<!\d)(?:(?:(?:1[6-9]|[2-9]\d)?\d{2})(?:(?:(?:0[13578]|1[02])31)|(?:(?:0[1,3-9]|1[0-2])(?:29|30)))|(?:(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00)))0229)|(?:(?:1[6-9]|[2-9]\d)?\d{2})(?:(?:0?[1-9])|(?:1[0-2]))(?:0?[1-9]|1\d|2[0-8]))(?!\d)

(check the demo)


Total madness simplified (years 2000-2099)

If you want you can simplify it to only work for years between 2000 and 2099.

(?<!\d)(?:(?:20\d{2})(?:(?:(?:0[13578]|1[02])31)|(?:(?:0[1,3-9]|1[0-2])(?:29|30)))|(?:(?:20(?:0[48]|[2468][048]|[13579][26]))0229)|(?:20\d{2})(?:(?:0?[1-9])|(?:1[0-2]))(?:0?[1-9]|1\d|2[0-8]))(?!\d)

But as you can see it's not really more simple.

(check the demo)


The sane way (years *)

To keep your sanity you should stick to a very simple regex and then validate it using code.

(20\d{2})(\d{2})(\d{2})

(check the demo)

Community
  • 1
  • 1
enrico.bacis
  • 27,413
  • 7
  • 76
  • 108
  • + for the "sane" way! I'd be tempted to perform a sanity test in regex, and then (where required) use a different method to navigate and calendar *weirdness*. – Thomas Kimber Oct 22 '18 at 08:45
  • Why not `(20\d{6})` for the last one? – IanS Dec 12 '18 at 11:22
  • @IanS Why not? Because I want three separate capturing groups so that I can use the separate matches for year, month, and day when creating a date object. Example: `new Date(match[1], match[2] - 1, match[3])` – Keven Apr 14 '21 at 23:25
1

My way (not the sane way)

(((\d{4})(0[13578]|10|12)(0[1-9]|[12][0-9]|3[01]))|((\d{4})(0[469]|11)(0[1-9]|[12][0-9]|30))|((\d{4})(02)(0[1-9]|1[0-9]|2[0-8]))|([0-9][0-9][02468]40229)|([0-9][0-9][02468]80229)|([0-9][0-9][13579]20229)|([0-9][0-9][13579]60229)|([0-9][0-9][02468]00229))

With vb.net (more easy to understand, I think so)

    Dim meses31 As String = "((\d{4})(0[13578]|10|12)(0[1-9]|[12][0-9]|3[01]))"
    Dim meses30 As String = "((\d{4})(0[469]|11)(0[1-9]|[12][0-9]|30))"
    Dim febrero28 As String = "((\d{4})(02)(0[1-9]|1[0-9]|2[0-8]))"
    Dim febrero29 As String = "([0-9][0-9][02468]40229)|([0-9][0-9][02468]80229)|([0-9][0-9][13579]20229)|([0-9][0-9][13579]60229)|([0-9][0-9][02468]00229)"

    Dim patternFecha As String = String.Concat("(", meses31, "|", meses30, "|", febrero28, "|", febrero29, ")")
Fran
  • 81
  • 10