1

I came up with the following PCRE regex:

[12]\d{3}(-)?(?(1)(0[1-9]|1[0-2]))(-)?(?(3)(0[1-9]|[12]\d|3[01]))

It matches the following date formats:

  • 2018-10-03
  • 2011-03
  • 2003

As you can see, I'm using conditional statements to detect whether there's a dash indicating a next part of the date. Unfortunately, javascript doesn't support conditional statements. How can I convert this to RegExp? I've tried using non-capturing groups containing alternatives, but I didn't manage to do it.

EDIT:

I can't use any JS functions because the regex will be used in the pattern HTML5 input property.

Tomasz Kasperczyk
  • 1,991
  • 3
  • 22
  • 43

3 Answers3

3

You can use this regex:

[12]\d{3}(?:(?:-(?:0[1-9]|1[0-2]))(?:-(?:0[1-9]|[12]\d|3[01]))?)?

Basically it matches a year, then creates a non capturing Group with the month and the date. The date part is optional in this Group, and the Whole Group with month and date is also optional.

That Means it will match years alone, years and month alone and full dates with year, month and date.

Edit (added anchors):

^[12]\d{3}(?:(?:-(?:0[1-9]|1[0-2]))(?:-(?:0[1-9]|[12]\d|3[01]))?)?$

Now it won't match '2018-aaa'.

Poul Bak
  • 10,450
  • 5
  • 32
  • 57
1

Here is non-regex version I felt like making

var dates = ["2018-10-03","2011-03","2003","12234"]

function isDate(str) {
  var parts = str.split("-"), 
      d = new Date(parts[0],parts.length>1?parts[1]-1:0,parts.length==3?parts[2]:1,12,0,0,0),
      yearOk=parts[0] < 3000 && d.getFullYear()==parts[0]; // or whatever test
  if (parts.length==1) return yearOk;
  var monthOk = +parts[1] == d.getMonth()+1;
  if (parts.length==2) return yearOk && monthOk;
  return yearOk && monthOk &&  +parts[2] == d.getDate();
}
dates.forEach(function(dStr) { console.log(isDate(dStr)) })
mplungjan
  • 169,008
  • 28
  • 173
  • 236
0

Regex for YYYY-MM-DD pattern with optional month and day

var regex = /((([12]\d{3})(-(0[1-9]|1[0-2]))*)(-(0[1-9]|[12]\d|3[01]))*)/;
front_end_dev
  • 1,998
  • 1
  • 9
  • 14