92

I know there are a lot of regex threads out there by I need a specific pattern I couldn't fin anywhere

This regex validates in a YYYY-MM-DD format

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

I need the pattern to be DD/MM/YYYY (day first since it's in spanish and only "/", "-" should not be allowed)

I searched several regex libraries and I think this one should work... but since I'm not familiar with regex I'm not sure it validates like that

(0[1-9]|[12][0-9]|3[01])[ \.-](0[1-9]|1[012])[ \.-](19|20|)\d\d

I also don't know ho to escape the slashes, I try to "see" the logic in the string but it's like trying "see" the Matrix code for me. I'm placing the regex string in a options .js

[...]  },
"date": {
                    "regex": (0[1-9]|[12][0-9]|3[01])[ \.-](0[1-9]|1[012])[ \.-](19|20|)\d\d,
                    "alertText": "Alert text AAAA-MM-DD"
                },
"other type..."[...]

So, if the regex is ok, how would I escape it? if it's not, what's the correct regex and how do I escape it? :P

Thanks a lot

3
  • 3
    Are you sure regex is the best option here? Commented Mar 28, 2011 at 21:39
  • 1
    Possible duplicate of Regex to validate date format dd/mm/yyyy Commented Sep 3, 2016 at 19:34
  • 1
    Use (((0[1-9]|[12][0-9]|3[01])([/])(0[13578]|10|12)([/])(\d{4}))|(([0][1-9]|[12][0-9]|30)([/])(0[469]|11)([/])(\d{4}))|((0[1-9]|1[0-9]|2[0-8])([/])(02)([/])(\d{4}))|((29)(\/)(02)([/])([02468][048]00))|((29)([/])(02)([/])([13579][26]00))|((29)([/])(02)([/])([0-9][0-9][0][48]))|((29)([/])(02)([/])([0-9][0-9][2468][048]))|((29)([/])(02)([/])([0-9][0-9][13579][26]))) to validate date in DD/MM/YYYY format, Even this will works for Leay year validation such as, this will be validate 29/02/2020 but not 29/02/2019 and also not 29/02/2100 Commented Apr 17, 2020 at 16:18

14 Answers 14

122

You could take the regex that validates YYYY/MM/DD and flip it around to get what you need for DD/MM/YYYY:

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

BTW - this regex validates for either DD/MM/YYYY or DD-MM-YYYY

P.S. This will allow dates such as 31/02/4899

Sign up to request clarification or add additional context in comments.

4 Comments

I tried flip it around but I wasn't sure where did each block started. Can this regex be edited to allow / / but not - - ? Thanks!
^(0?[1-9]|[12][0-9]|3[01])[\/](0?[1-9]|1[012])[\/\-]\d{4}$ Regex if you just want to accept DD/MM/YYYY and not DD-MM-YYYY
No match on 06/20/2016 either.
See @OammieR's answer for a more comprehensive regex. stackoverflow.com/a/14807681/246616
47

A regex is good for matching the general format but I think you should move parsing to the Date class, e.g.:

function parseDate(str) {
  var m = str.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/);
  return (m) ? new Date(m[3], m[2]-1, m[1]) : null;
}

Now you can use this function to check for valid dates; however, if you need to actually validate without rolling (e.g. "31/2/2010" doesn't automatically roll to "3/3/2010") then you've got another problem.

[Edit] If you also want to validate without rolling then you could add a check to compare against the original string to make sure it is the same date:

function parseDate(str) {
  var m = str.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/)
    , d = (m) ? new Date(m[3], m[2]-1, m[1]) : null
    , nonRolling = (d&&(str==[d.getDate(),d.getMonth()+1,d.getFullYear()].join('/')));
  return (nonRolling) ? d : null;
}

[Edit2] If you want to match against zero-padded dates (e.g. "08/08/2013") then you could do something like this:

function parseDate(str) {
  function pad(x){return (((''+x).length==2) ? '' : '0') + x; }
  var m = str.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/)
    , d = (m) ? new Date(m[3], m[2]-1, m[1]) : null
    , matchesPadded = (d&&(str==[pad(d.getDate()),pad(d.getMonth()+1),d.getFullYear()].join('/')))
    , matchesNonPadded = (d&&(str==[d.getDate(),d.getMonth()+1,d.getFullYear()].join('/')));
  return (matchesPadded || matchesNonPadded) ? d : null;
}

However, it will still fail for inconsistently padded dates (e.g. "8/08/2013").

3 Comments

Nice idea! Only problem I found was '08/08/2013' won't pass the nonRolling validation because of the zeros.
No need to rebuild the string. Just d.getDate() == m[1] && d.getMonth() == m[2] && d.getFullYear() == m[3]
/^(\d{1,2})\/(\d{1,2})\/(?:\d{4}|\d{2})$/ ... I also wanted to pass dates having two or 4 digits. Nothing special simply addition at the end (?:\d{4}|\d{2}). I then also wanted to pass dates that contained hyphens or backslashes [/|-] so the FULL syntax ended looking like this... ^(\d{1,2})[/|-](\d{1,2})[/|-](?:\d{4}|\d{2})$
45

Take a look from here https://www.regextester.com/?fam=114662

Use this following Regular Expression Details, This will support leap year also.

var reg = /^(((0[1-9]|[12]\d|3[01])\/(0[13578]|1[02])\/((19|[2-9]\d)\d{2}))|((0[1-9]|[12]\d|30)\/(0[13456789]|1[012])\/((19|[2-9]\d)\d{2}))|((0[1-9]|1\d|2[0-8])\/02\/((19|[2-9]\d)\d{2}))|(29\/02\/((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|(([1][26]|[2468][048]|[3579][26])00))))$/g;

Example

3 Comments

This works like a charm. Tested a lot of dates and its works with leap years and also for months with 30 or 31 days.
Unfortunately this fails for years earlier than 1900. For instance 01/01/1899 fails. Am I missing something here?
what if I want to check this format DD/MM/YYYY instead of MM/DD/YYYY?
20

Scape slashes is simply use \ before / and it will be escaped. (\/=> /).

Otherwise you're regex DD/MM/YYYY could be next:

/^[0-9]{2}[\/]{1}[0-9]{2}[\/]{1}[0-9]{4}$/g

Explanation:

  • [0-9]: Just Numbers
  • {2} or {4}: Length 2 or 4. You could do {2,4} as well to length between two numbers (2 and 4 in this case)
  • [\/]: Character /
  • g : Global -- Or m: Multiline (Optional, see your requirements)
  • $: Anchor to end of string. (Optional, see your requirements)
  • ^: Start of string. (Optional, see your requirements)

An example of use:

var regex = /^[0-9]{2}[\/][0-9]{2}[\/][0-9]{4}$/g;

var dates = ["2009-10-09", "2009.10.09", "2009/10/09", "200910-09", "1990/10/09", 
    "2016/0/09", "2017/10/09", "2016/09/09", "20/09/2016", "21/09/2016", "22/09/2016",
    "23/09/2016", "19/09/2016", "18/09/2016", "25/09/2016", "21/09/2018"];

//Iterate array
dates.forEach(
    function(date){
        console.log(date + " matches with regex?");
      console.log(regex.test(date));
    });

Of course you can use as boolean:

if(regex.test(date)){
     //do something
}

3 Comments

your first test does not pass
There are many valid dates that does not pass your regExp test
You wrote all this nice code yet none of it works when you run it. Did you check your work before posting?
11

I use this function for dd/mm/yyyy format :

// (new Date()).fromString("3/9/2013") : 3 of september
// (new Date()).fromString("3/9/2013", false) : 9 of march
Date.prototype.fromString = function(str, ddmmyyyy) {
    var m = str.match(/(\d+)(-|\/)(\d+)(?:-|\/)(?:(\d+)\s+(\d+):(\d+)(?::(\d+))?(?:\.(\d+))?)?/);
    if(m[2] == "/"){
        if(ddmmyyyy === false)
            return new Date(+m[4], +m[1] - 1, +m[3], m[5] ? +m[5] : 0, m[6] ? +m[6] : 0, m[7] ? +m[7] : 0, m[8] ? +m[8] * 100 : 0);
        return new Date(+m[4], +m[3] - 1, +m[1], m[5] ? +m[5] : 0, m[6] ? +m[6] : 0, m[7] ? +m[7] : 0, m[8] ? +m[8] * 100 : 0);
    }
    return new Date(+m[1], +m[3] - 1, +m[4], m[5] ? +m[5] : 0, m[6] ? +m[6] : 0, m[7] ? +m[7] : 0, m[8] ? +m[8] * 100 : 0);
}

Comments

9

Try using this..

[0-9]{2}[/][0-9]{2}[/][0-9]{4}$

this should work with this pattern DD/DD/DDDD where D is any digit (0-9)

1 Comment

Consider providing an explanation to your regexp
3
((?=\d{4})\d{4}|(?=[a-zA-Z]{3})[a-zA-Z]{3}|\d{2})((?=\/)\/|\-)((?=[0-9]{2})[0-9]{2}|(?=[0-9]{1,2})[0-9]{1,2}|[a-zA-Z]{3})((?=\/)\/|\-)((?=[0-9]{4})[0-9]{4}|(?=[0-9]{2})[0-9]{2}|[a-zA-Z]{3})

Regex Compile on it

2012/22/Jan
2012/22/12 
2012/22/12
2012/22/12
2012/22/12
2012/22/12
2012/22/12
2012-Dec-22
2012-12-22
23/12/2012
23/12/2012
Dec-22-2012
12-2-2012
23-12-2012
23-12-2012

Comments

1

If you are in Javascript already, couldn't you just use Date.Parse() to validate a date instead of using regEx.

RegEx for date is actually unwieldy and hard to get right especially with leap years and all.

3 Comments

I need regex because I'm using position-absolute.com/articles/…
Could you elaborate since that article is huge?
Date.parse doesn't seem to work with UK date format (dd/mm/yyyy) on Chrome. It only works with US format (mm/dd/yyyy).
1

For people who needs to validate years earlier than year 1900, following should do the trick. Actually this is same as the above answer given by [@OammieR][1] BUT with years including 1800 - 1899.

/^(((0[1-9]|[12]\d|3[01])\/(0[13578]|1[02])\/((19|[2-9]\d)\d{2}))|((0[1-9]|[12]\d|3[01])\/(0[13578]|1[02])\/((18|[2-9]\d)\d{2}))|((0[1-9]|[12]\d|30)\/(0[13456789]|1[012])\/((19|[2-9]\d)\d{2}))|((0[1-9]|[12]\d|30)\/(0[13456789]|1[012])\/((18|[2-9]\d)\d{2}))|((0[1-9]|1\d|2[0-8])\/02\/((19|[2-9]\d)\d{2}))|(29\/02\/((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))$/

Hope this helps someone who needs to validate years earlier than 1900, such as 01/01/1855, etc.

Thanks @OammieR for the initial idea.

Comments

1

Here you go, an unfailing regex that works on all valid YYYY/MM/DD (bonus for regex for YYYY-MM-DD inputs) (including only VALID leap days):

This lovely piece matches ONLY valid dates (and accounts for leap years - and discounts those leap years which occur on centennial years which are not wholly divisible by 400 (thus rendering them ineligible for a February 29th).

I have included non-delimited, as well as slash and dash delimited variants for the YYYYMMDD, MMDDYYYY, and DDMMYYYY variations that are commonly seen.

These have been thoroughly tested against all numeric combinations from "0000-00-00" through "9999-99-99" without issue. See the section "testing" below.


Non-Delimited Variants:

YYYYMMDD:

/^(?:(?:(?:(?:(?:[02468][048])|(?:[13579][26]))00)|(?:[0-9][0-9](?:(?:0[48])|(?:[2468][048])|(?:[13579][26]))))0229)|(?:\d{4}(?:(?:(?:0[13578]|1[02])(?:0[1-9]|[12]\d|3[01]))|(?:(?:0[469]|11)(?:0[1-9]|[12]\d|30))|(?:02(?:0[1-9]|1[0-9]|2[0-8]))))$/

MMDDYYYY:

/^(?:0229(?:(?:(?:(?:[02468][048])|(?:[13579][26]))00)|(?:[0-9][0-9](?:(?:0[48])|(?:[2468][048])|(?:[13579][26])))))|(?:(?:(?:(?:0[13578]|1[02])(?:0[1-9]|[12]\d|3[01]))|(?:(?:0[469]|11)(?:0[1-9]|[12]\d|30))|(?:02(?:0[1-9]|1[0-9]|2[0-8])))\d{4})$/

DDMMYYYY:

/^(?:2902(?:(?:(?:(?:[02468][048])|(?:[13579][26]))00)|(?:[0-9][0-9](?:(?:0[48])|(?:[2468][048])|(?:[13579][26])))))|(?:(?:(?:0[1-9]|[12]\d|3[01])(?:(?:0[13578]|1[02]))|(?:(?:0[1-9]|[12]\d|30)(?:0[469]|11))|(?:(?:0[1-9]|1[0-9]|2[0-8])02))\d{4})$/

Forward Slash Delimited Variants:

YYYY/MM/DD:

/^(?:(?:(?:(?:(?:[02468][048])|(?:[13579][26]))00)|(?:[0-9][0-9](?:(?:0[48])|(?:[2468][048])|(?:[13579][26]))))[/]02[/]29)|(?:\d{4}[/](?:(?:(?:0[13578]|1[02])[/](?:0[1-9]|[12]\d|3[01]))|(?:(?:0[469]|11)[/](?:0[1-9]|[12]\d|30))|(?:02[/](?:0[1-9]|1[0-9]|2[0-8]))))$/

MM/DD/YYYY:

/^(?:02[/]29[/](?:(?:(?:(?:[02468][048])|(?:[13579][26]))00)|(?:[0-9][0-9](?:(?:0[48])|(?:[2468][048])|(?:[13579][26])))))|(?:(?:(?:(?:0[13578]|1[02])[/](?:0[1-9]|[12]\d|3[01]))|(?:(?:0[469]|11)[/](?:0[1-9]|[12]\d|30))|(?:02[/](?:0[1-9]|1[0-9]|2[0-8])))[/]\d{4})$/

DD/MM/YYYY:

/^(?:29[/]02[/](?:(?:(?:(?:[02468][048])|(?:[13579][26]))00)|(?:[0-9][0-9](?:(?:0[48])|(?:[2468][048])|(?:[13579][26])))))|(?:(?:(?:0[1-9]|[12]\d|3[01])[/](?:(?:0[13578]|1[02]))|(?:(?:0[1-9]|[12]\d|30)[/](?:0[469]|11))|(?:(?:0[1-9]|1[0-9]|2[0-8])[/]02))[/]\d{4})$/

Dash Delimited Variants:

YYYY-MM-DD:

/^(?:(?:(?:(?:(?:[02468][048])|(?:[13579][26]))00)|(?:[0-9][0-9](?:(?:0[48])|(?:[2468][048])|(?:[13579][26]))))[-]02[-]29)|(?:\d{4}[-](?:(?:(?:0[13578]|1[02])[-](?:0[1-9]|[12]\d|3[01]))|(?:(?:0[469]|11)[-](?:0[1-9]|[12]\d|30))|(?:02[-](?:0[1-9]|1[0-9]|2[0-8]))))$/

MM-DD-YYYY:

/^(?:02[-]29[-](?:(?:(?:(?:[02468][048])|(?:[13579][26]))00)|(?:[0-9][0-9](?:(?:0[48])|(?:[2468][048])|(?:[13579][26])))))|(?:(?:(?:(?:0[13578]|1[02])[-](?:0[1-9]|[12]\d|3[01]))|(?:(?:0[469]|11)[-](?:0[1-9]|[12]\d|30))|(?:02[-](?:0[1-9]|1[0-9]|2[0-8])))[-]\d{4})$/

DD-MM-YYYY

/^(?:29[-]02[-](?:(?:(?:(?:[02468][048])|(?:[13579][26]))00)|(?:[0-9][0-9](?:(?:0[48])|(?:[2468][048])|(?:[13579][26])))))|(?:(?:(?:0[1-9]|[12]\d|3[01])[-](?:(?:0[13578]|1[02]))|(?:(?:0[1-9]|[12]\d|30)[-](?:0[469]|11))|(?:(?:0[1-9]|1[0-9]|2[0-8])[-]02))[-]\d{4})$/

Testing

It has also been thoroughly tested against all possible combinations of YYYY-MM-DD, from 0000-00-00 through 9999-99-99.

Crucially, it also aligns with JavaScript's produced Date objects when passed those dates. Thus, no Date object can exist between 0000-01-01 through 9999-12-31 which is not validated correctly by this regular expression.

This has been produced using non-capturing groups, as attempting to capture would (effectively) be pointless, due to the indexed nature of capturing groups. Don't bother, just separate the string by indexes (minding to skip the hyphens) if you need the "YYYY"/"MM"/"DD" strings for whatever reason. And, if we're not going to use them, we might as well save the compute on it.

Enjoy. Explanation below.

Note, the explanation is focused on the YYYY-MM-DD regex, but both work precisely the same way. The only difference is the delimiter.


Leap Day Matching:

The Regex:

    /(?:(?:(?:(?:(?:[02468][048])|(?:[13579][26]))00)|(?:[0-9][0-9](?:(?:0[48])|(?:[2468][048])|(?:[13579][26]))))-02-29)/

The Trick

Rationale: if a number's last two digits are evenly divisible by 4, the whole number is evenly divisible by 4.
If we look at all numbers (left-padded zero) between 00-99, we can separate them into two distinct groups

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
  1. Two digit pairs with an even leading digit, which will always be trailed by either 0, 4, or 8: /[02468][048]/
  2. Two digit pairs with an odd leading digit, which will always be trailed by either 2 or 6: /[13579][26]/

Centennial Years

We can use that to isolate those valid centennial years, whereby the year is wholly divisible by both 100 and 400. The last two digits are always double-zero, so we only care about the first two digits, which means they must fit the above trend of an even digit followed by [048] or an odd digit followed by [26]:

/(?:(?:(?:[02468][048])|(?:[13579][26]))00)/

Non-Centennial Years

Now we want to take the same logic and allow it to capture any combination of [0-9] for the first two digits of the year, and any combination of the above "trick" for the last two digits of the year: (/[02468][048]|[13579][26]/).

The only difference is that we DON'T capture years ending in double-zero for this part of the regex, which gives us the expression:

/(?:[0-9][0-9](?:(?:0[48])|(?:[2468][048])|(?:[13579][26])))/

All together: February 29th

Then, to put it all together, as we know leap days can ONLY be on February 29th, we just tack on /-02-29/ at the end of the group, giving us the full expression for only VALID leap days.


Matching Valid Non-Leap Days

/(?:\d{4}-(?:(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01]))|(?:(?:0[469]|11)-(?:0[1-9]|[12]\d|30))|(?:(02)-(?:0[1-9]|1[0-9]|2[0-8]))))/

This is the easy part, now that leap-days are out of the equation.

The Year:

We literally just want any combination of 4 digits followed by a dash:

/\d{4}-/

Then we account for the different combinations of months with their maximum number of days.

31 Day Months

The months with 31 days are:

01 03 05 07 08 10 12

So, we make sure the month is one of those, followed by a hyphen:

/(?:0[13578]|1[02])-/

And that the days are anywhere between 01-31:

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

Giving us:

/(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01]))/

30 Day Months:

Next up, we have the 30 day months:

04 06 09 11

So, basically the same tact, just with different targets. First the month followed by a dash:

/(?:0[469]|11)-/

Then the days, which must be between 01-30:

/(?:0[1-9]|[12]\d|30)/

Giving us:

/(?:(?:0[469]|11)-(?:0[1-9]|[12]\d|30))/

28 Day Months:

Finally, we have our last part, the only 28 day month there is. This one is much simpler, so I'm not going to separate it like I did the others:

/(?:02)-(?:0[1-9]|1[0-9]|2[0-8]))/

Finally, if we put it all together, we get the abomination at the top.

Comments

0

Do the following change to the jquery.validationengine-en.js file and update the dd/mm/yyyy inline validation by including leap year:

"date": {
    // Check if date is valid by leap year
    "func": function (field) {
    //var pattern = new RegExp(/^(\d{4})[\/\-\.](0?[1-9]|1[012])[\/\-\.](0?[1-9]|[12][0-9]|3[01])$/);
    var pattern = new RegExp(/^(0?[1-9]|[12][0-9]|3[01])[\/\-\.](0?[1-9]|1[012])[\/\-\.](\d{4})$/);
    var match = pattern.exec(field.val());
    if (match == null)
    return false;

    //var year = match[1];
    //var month = match[2]*1;
    //var day = match[3]*1;
    var year = match[3];
    var month = match[2]*1;
    var day = match[1]*1;
    var date = new Date(year, month - 1, day); // because months starts from 0.

    return (date.getFullYear() == year && date.getMonth() == (month - 1) && date.getDate() == day);
},
"alertText": "* Invalid date, must be in DD-MM-YYYY format"

Comments

0

I build this regular to check month 30/31 and let february to 29.

new RegExp(/^((0[1-9]|[12][0-9]|3[01])(\/)(0[13578]|1[02]))|((0[1-9]|[12][0-9])(\/)(02))|((0[1-9]|[12][0-9]|3[0])(\/)(0[469]|11))(\/)\d{4}$/)

I think, it's more simple and more flexible and enough full.

Perhaps first part can be contract but I Don't find properly.

Comments

0

This validates date like dd-mm-yyyy

([0-2][0-9]|(3)[0-1])(\-)(((0)[0-9])|((1)[0-2]))(\-)([0-9][0-9][0-9][0-9])

This can use with javascript like angular reactive forms

Comments

-1

It can be done like this for dd/mm/yyyy:

^(3[01]|[12][0-9]|0[1-9])/(1[0-2]|0[1-9])/[0-9]{4}$

For mm/dd/yy, mm/dd/yyyy, dd/mm/yy, and dd/mm/yyyy:

Allowing leading zeros to be omitted:

^[0-3]?[0-9]/[0-3]?[0-9]/(?:[0-9]{2})?[0-9]{2}$

Requiring leading zeros:

^[0-3][0-9]/[0-3][0-9]/(?:[0-9][0-9])?[0-9][0-9]$

For more details: https://www.oreilly.com/library/view/regular-expressions-cookbook/9781449327453/ch04s04.html

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.