Reputation: 3267
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
Upvotes: 92
Views: 371303
Reputation: 66
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.
/^(?:(?:(?:(?:(?:[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]))))$/
/^(?: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})$/
/^(?: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})$/
/^(?:(?:(?:(?:(?:[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]))))$/
/^(?: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})$/
/^(?: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})$/
/^(?:(?:(?:(?:(?:[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]))))$/
/^(?: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})$/
/^(?: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})$/
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.
/(?:(?:(?:(?:(?:[02468][048])|(?:[13579][26]))00)|(?:[0-9][0-9](?:(?:0[48])|(?:[2468][048])|(?:[13579][26]))))-02-29)/
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
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)/
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])))/
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.
/(?:\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.
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.
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]))/
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))/
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.
Upvotes: 0
Reputation: 7129
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
Upvotes: -1
Reputation: 320
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
Upvotes: 0
Reputation: 2850
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;
Upvotes: 45
Reputation: 16106
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
[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
}
Upvotes: 20
Reputation: 622
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.
Upvotes: 0
Reputation: 163
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)
Upvotes: 9
Reputation: 124
((?=\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
Upvotes: 3
Reputation: 9201
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.
Upvotes: 1
Reputation: 1
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"
Upvotes: 0
Reputation: 359
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);
}
Upvotes: 11
Reputation: 156434
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").
Upvotes: 47
Reputation: 3250
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.
Upvotes: 1
Reputation: 50185
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
Upvotes: 122