UK Date Regular Expression [duplicate] - regex

This question already has answers here:
Does anyone know of a reg expression for uk date format
(7 answers)
Closed 9 years ago.
I'm trying to create a regular expression that validates UK date format. I have the following:
(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.](19|20)\d\d
This works great for validating: 09/12/2011. But if the date is: 9/12/2011 it will not validate correctly. Is there a regular expression that allows me to use a single number and two numbers for the day section? For example "09" and "9".

Just make the leading 0 optional:
(0?[1-9]|[12][0-9]|3[01])[- /.](0?[1-9]|1[012])[- /.](19|20)\d\d
You will need an additional validation step, though - this regex of course won't check for invalid dates like 31-02-2000 etc. While it's possible to do this in regex, it's not recommended because it's much easier to do this programmatically, and that regex is going to be monstrous. Here is a date validating regex (that uses the mmddyyyy format, though) to show what I mean.

My preference goes to a combination of the simple regex, (\d{1,2})[-/.](\d{1,2})[-/.](\d{4}), with some code that validates that this is indeed a correct date. You will have to have that code anyways, unless you want to make a monstrous regex that rejects "29-02-2011" but not "29-02-2008".
Anyway, here's a breakdown of that regex so you can see what's going on:
\d{1,2}: this part matches one or two ({1,2}) digits (\d), making up the day portion of the date.
[-/.]: this matches one of the characters inside the brackets, i.e, either a ., a /, or a -.
\d{1,2}: again, this matches one or two digits from the month.
[-/.]: another separator...
\d{4}: this matches exactly four ({4}) digits for the year portion.
Note that the day, month, and year portion of the regular expression are inside parentheses. This is to create groups. Each of those three portions will be captured into a group that you can retrieve from the match. Groups are identified with a number, starting with 1, from left to right. This means that the day will be group 1, the month group 2, and the year group 3. There is also a group 0 that always contains the entire text matched.
You can use the groups to perform the second part of the validation and reject invalid dates like "30-02-2011", "31-4-2011", or "32-13-2011".
If you want to reject inputs that use two different separators, like "31-12.2011", you can use a slightly more advanced feature called backreferences:
(\d{1,2})([-/.])(\d{1,2})\2(\d{4})
Note that now I placed the first separator inside a group. This changes the month to group 3, and the year to group 4. The separator is matched by group 2. The backreference is that \2 part between the month and the year. It matches whatever was matched by the 2nd previous group. If you walk back two groups from the backreference you end up in group 2, the separator. If that group matched a ., the backreference with match only a . as well; if it matched a -, the backreference will match only a -; and so on.

What is "the UK date format" anyway?
Officially, it's 2011-02-21 today, see BS EN 28601 / ISO 8601.
On the web, you should all be using the format defined in RFC 3339.

Correct way to check for the day is to ban the [4-9]. numbers too.
Something like 0[0-9]|[12][0-9]|3[01]|[^0-9][0-9]|^[0-9]

Yes. {n,m} is the quantifier that say "at least n element, max m elements". So you can write \d{1,2} (matches 1 or 2 digits). Complete date: \d{1,2}/\d{1,2}/\d{4}
Alternative: Make the leading zero optional:
0?\d/0?\d/\d{4}
The question mark says, that the element before the question mark is optional.

Use this code, I am validating everything for the date. :-
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class FinalDateValidator {
private Pattern pattern;
private Matcher matcher;
public boolean isValidDate(final String date) {
Pattern pattern;
Matcher matcher;
final String DATE_PATTERN = "([0-9]{4})/(0?[1-9]|1[012])/(0[1-9]|[12][0-9]|3[01]|[1-9])";
pattern = Pattern.compile(DATE_PATTERN);
matcher = pattern.matcher(date);
if (matcher.matches()) {
matcher.reset();
if (matcher.find()) {
int year = Integer.parseInt(matcher.group(1));
String month = matcher.group(2);
String day = matcher.group(3);
System.out.println("__________________________________________________");
System.out.println("year : "+year +" month : "+month +" day : "+day);
if (day.equals("31")
&& (month.equals("4") || month.equals("6")
|| month.equals("9") || month.equals("11")
|| month.equals("04") || month.equals("06") || month
.equals("09"))) {
return false; // only 1,3,5,7,8,10,12 has 31 days
} else if (month.equals("2") || month.equals("02")) {
// leap year
if (year % 4 == 0) {
if (day.equals("30") || day.equals("31")) {
return false;
} else {
return true;
}
} else {
if (day.equals("29") || day.equals("30")
|| day.equals("31")) {
return false;
} else {
return true;
}
}
} else {
return true;
}
} else {
return false;
}
} else {
return false;
}
}
public static void main(String argsp[]){
FinalDateValidator vs = new FinalDateValidator();
System.out.println("1: 1910/12/10---"+vs.isValidDate("1910/12/10"));
System.out.println("2: 2010/2/29---"+vs.isValidDate("2010/02/29"));
System.out.println("3: 2011/2/29---"+vs.isValidDate("2011/02/29"));
System.out.println("3: 2011/2/30---"+vs.isValidDate("2011/02/30"));
System.out.println("3: 2011/2/31---"+vs.isValidDate("2011/02/31"));
System.out.println("4: 2010/08/31---"+vs.isValidDate("2010/08/31"));
System.out.println("5: 2010/3/10---"+vs.isValidDate("2010/03/10"));
System.out.println("6: 2010/03/33---"+vs.isValidDate("2010/03/33"));
System.out.println("7: 2010/03/09---"+vs.isValidDate("2010/03/09"));
System.out.println("8: 2010/03/9---"+vs.isValidDate("2010/03/9"));
System.out.println("9: 1910/12/00---"+vs.isValidDate("1910/12/00"));
System.out.println("10: 2010/02/01---"+vs.isValidDate("2010/02/01"));
System.out.println("11: 2011/2/03---"+vs.isValidDate("2011/02/03"));
System.out.println("12: 2010/08/31---"+vs.isValidDate("2010/08/31"));
System.out.println("13: 2010/03/39---"+vs.isValidDate("2010/03/39"));
System.out.println("14: 201011/03/31---"+vs.isValidDate("201011/03/31"));
System.out.println("15: 2010/032/09---"+vs.isValidDate("2010/032/09"));
System.out.println("16: 2010/03/922---"+vs.isValidDate("2010/03/922"));
}
}
Enjoy...

I ran into the similar requirements.
Here is the complete regular expression along with Leap Year validation.
Format: dd/MM/yyyy
(3[01]|[12]\d|0[1-9])/(0[13578]|10|12)/((?!0000)\d{4})|(30|[12]\d|0[1-9])/(0[469]|11)/((?!0000)\d{4})|(2[0-8]|[01]\d|0[1-9])/(02)/((?!0000)\d{4})|
29/(02)/(1600|2000|2400|2800|00)|29/(02)/(\d\d)(0[48]|[2468][048]|[13579][26])
It can be easily modified to US format or other EU formats.

Related

.NET Core - regex matches whole string instead of group [duplicate]

This question already has answers here:
Returning only part of match from Regular Expression
(4 answers)
Closed 2 years ago.
I tested my regex on regex101.com, it returns 3 groups
text :
<CloseResponse>SESSION_ID</CloseResponse>
regex :
(<.*>)([\s\S]*?)(<\/.*>)
in C#, I get only one match and one group that contains the whole string instead of just the SESSION_ID
I expect the code to return only SESSION_ID
I tried finding a global option but there don't seem to be any
here is my code
Regex rg = new Regex(#"<.*>([\s\S]*?)<\/.*>");
MatchCollection matches = rg.Matches(tag);
if (matches.Count > 0) ////////////////////////////////// only one match
{
if (matches[0].Groups.Count > 0)
{
Group g = matches[0].Groups[0];
return g.Value; //////////////////// = <CloseResponse>SESSION_ID</CloseResponse>
}
}
return null;
thanks for helping me on this
I managed to make it work this way
string input = "<OpenResult>SESSION_ID</OpenResult>";
// ... Use named group in regular expression.
Regex expression = new Regex(#"(<.*>)(?<middle>[\s\S]*)(<\/.*>)");
// ... See if we matched.
Match match = expression.Match(input);
if (match.Success)
{
// ... Get group by name.
string result = match.Groups["middle"].Value;
Console.WriteLine("Middle: {0}", result);
}
// Done.
Console.ReadLine();
Use non-capturing group if you want whole string as result: (?:)
(?:<.*>)(?:[\s\S]*?)(?:<\/.*>)
Demo
If you just want to capture session id use this:
(?:<.*>)([\s\S]*?)(?:<\/.*>)
Demo

How can I build regex for an specific format, that works fine in edition

I have to do a regular expression for this format.
002-251285-0008P
the first three digits are a zone code could be any number but just 3 digit. after and only after I can add "-".
Then the six digits are a date in sets of two digit 25 - day, 12 - month, and 85 - year (the last 2 digits
it would be 1985) after that I can add "-".
the last group is another code formed by 4 numero and a letter.
I wanted to checking while a textfield is being edited. but always something shows up.
I will put some of my tries but thing like, "I can add '-' at beginning" or 'it doesn't match until I have the complete format so the textfield is never written'
^\$|^([0-9]{0,3})(\\-)?([0-9]{0,6})\$
^\$|^([0-9]{3})(\\-[0-9]{0,6})\$
they aren't complete they just the first to group, but or they to strict and don't allow me to enter just numbre o they are to soft and allow me to enter "-" at the start.
every help is appreciated.
Edit
Here is how i use the regex
Here I declare all my regex strings:
class Regex{
String regexNumerocondosdecimales = "^\$|^(0|([1-9][0-9]{0,3}))(\\.[0-9]{0,2})?\$";
String regexSoloLetrasyEpacios = "[a-zA-Z \s]{0,30}";
String regexSoloNumeros = "^\$|^(0|([1-9][0-9]{0,1}))\$";
String regexCedula = "r'^\d{1,3}(?:-(?:\d{1,6}(?:-(?:\d{1,4}P?)?)?)?)?\$'";
String regexLetrasyNumeros = "[a-zA-Z0-9 \s]{0,200}";
String regexCelular = "^[578] [0-9]{0,7}\$";
}
Here I set and validate it
abstract class ValidadorString{
bool esValido(String value);
}
class ValidadorRegex implements ValidadorString{
final String fuenteRegex;
ValidadorRegex({this.fuenteRegex});
bool esValido(String value){
try{
final regex = RegExp(fuenteRegex);
final matches = regex.allMatches(value);
for(Match match in matches){
if (match.start == 0 && match.end == value.length) {
return true;
}
}
return false;
} catch (e){
assert(false, e.toString());
return true;
}
}
}
Use
String regexCedula = '^([0-9]{1,3}(-([0-9]{1,6}(-([0-9]{1,4}[A-Za-z]?)?)?)?)?)?$';
See the regex demo
Details
^ - start of string
([0-9]{1,3}(-([0-9]{1,6}(-([0-9]{1,4}[A-Za-z]?)?)?)?)?)? - an optional sequence of
[0-9]{1,3} - 1, 2 or 3 digits
(-([0-9]{1,6}(-([0-9]{1,4}[A-Za-z]?)?)?)?)? - an optional occurrence of:
- - a hyphen
([0-9]{1,6}(-([0-9]{1,4}[A-Za-z]?)?)?)? - an optional occurrence of:
[0-9]{1,6} - one to six digits
(-([0-9]{1,4}[A-Za-z]?)?)? - an optional occurrence of:
- - a hyphen
([0-9]{1,4}[A-Za-z]?)? - an optional occurrence of 1 to 4 digits and then an optional ASCII letter
$ - end of string.

Multiple capture groups - all optional

I know this (or similar) has been asked a hundred times - but I really need help now :D
The strings the regex should match.
Note: n is in the range of INTEGER_MIN - INTEGER_MAX
{number}
{number(1-n)}
{number(1-n,-n-n)}
{number(1-n,-n-n,0-n)}
If the pattern matches it should result in 3 seperate capture groups, with this results.
All groups should be optional - so that if request in for example Java they return null.
1: 1-n
2: -n-n
3: 0-n
What I've tried:
\{number(?:\(([1-9])(?:(?:,)([0-9])){0,2}\))?\}
This obviously isn't right and is only containing 2 groups (m.groupCount())
Okay, from what I deduced, I would do this:
\{number(?:\((\-?\d+)(?:\,(\-?\d+))?(?:\,(\-?\d+))?\))?\}
Then carry out operations on the captured groups to valid the range of the integers such as...
[Pseudo code since I don't know what language you are using]
captured integers = "capture1", "capture2", "capture3"
if{("capture1" < "capture2" && "capture1" > "capture3") ||
("capture1" > "capture2" && "capture1" < "capture3")} {
Do something
} else {
Do something else; like reject or throw error
}

use regular expression to find and replace but only every 3 characters for DNA sequence

Is it possible to do a find/replace using regular expressions on a string of dna such that it only considers every 3 characters (a codon of dna) at a time.
for example I would like the regular expression to see this:
dna="AAACCCTTTGGG"
as this:
AAA CCC TTT GGG
If I use the regular expressions right now and the expression was
Regex.Replace(dna,"ACC","AAA") it would find a match, but in this case of looking at 3 characters at a time there would be no match.
Is this possible?
Why use a regex? Try this instead, which is probably more efficient to boot:
public string DnaReplaceCodon(string input, string match, string replace) {
if (match.Length != 3 || replace.Length != 3)
throw new ArgumentOutOfRangeException();
var output = new StringBuilder(input.Length);
int i = 0;
while (i + 2 < input.Length) {
if (input[i] == match[0] && input[i+1] == match[1] && input[i+2] == match[2]) {
output.Append(replace);
} else {
output.Append(input[i]);
output.Append(input[i]+1);
output.Append(input[i]+2);
}
i += 3;
}
// pick up trailing letters.
while (i < input.Length) output.Append(input[i]);
return output.ToString();
}
Solution
It is possible to do this with regex. Assuming the input is valid (contains only A, T, G, C):
Regex.Replace(input, #"\G((?:.{3})*?)" + codon, "$1" + replacement);
DEMO
If the input is not guaranteed to be valid, you can just do a check with the regex ^[ATCG]*$ (allow non-multiple of 3) or ^([ATCG]{3})*$ (sequence must be multiple of 3). It doesn't make sense to operate on invalid input anyway.
Explanation
The construction above works for any codon. For the sake of explanation, let the codon be AAA. The regex will be \G((?:.{3})*?)AAA.
The whole regex actually matches the shortest substring that ends with the codon to be replaced.
\G # Must be at beginning of the string, or where last match left off
((?:.{3})*?) # Match any number of codon, lazily. The text is also captured.
AAA # The codon we want to replace
We make sure the matches only starts from positions whose index is multiple of 3 with:
\G which asserts that the match starts from where the previous match left off (or the beginning of the string)
And the fact that the pattern ((?:.{3})*?)AAA can only match a sequence whose length is multiple of 3.
Due to the lazy quantifier, we can be sure that in each match, the part before the codon to be replaced (matched by ((?:.{3})*?) part) does not contain the codon.
In the replacement, we put back the part before the codon (which is captured in capturing group 1 and can be referred to with $1), follows by the replacement codon.
NOTE
As explained in the comment, the following is not a good solution! I leave it in so that others will not fall for the same mistake
You can usually find out where a match starts and ends via m.start() and m.end(). If m.start() % 3 == 0 you found a relevant match.

Regex to match an ISO 8601 datetime string

does anyone have a good regex pattern for matching iso datetimes?
ie: 2010-06-15T00:00:00
For the strict, full datetime, including milliseconds, per the W3C's take on the spec.:
//-- Complete precision:
/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/
//-- No milliseconds:
/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z)/
//-- No Seconds:
/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z)/
//-- Putting it all together:
/(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/
.
Additional variations allowed by the actual ISO 8601:2004(E) doc:
/********************************************
** No time-zone varients:
*/
//-- Complete precision:
/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+/
//-- No milliseconds:
/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d/
//-- No Seconds:
/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d/
//-- Putting it all together:
/(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+)|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d)|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d)/
WARNING: This all gets messy fast, and it still allows certain nonsense such as a 14th month.
Additionally, ISO 8601:2004(E) allows a several other variants.
.
"2010-06-15T00:00:00" isn't legal, because it doesn't have the time-zone designation.
For matching just ISO date, like 2017-09-22, you can use this regexp:
^\d{4}-([0]\d|1[0-2])-([0-2]\d|3[01])$
It will match any numeric year, any month specified by two digits in range 00-12 and any date specified by two digits in range 00-31
I reworked the top answer into something a bit more concise. Instead of writing out each of the three optional patterns, the elements are nested as optional statements.
/[+-]?\d{4}(-[01]\d(-[0-3]\d(T[0-2]\d:[0-5]\d:?([0-5]\d(\.\d+)?)?[+-][0-2]\d:[0-5]\dZ?)?)?)?/
I'm curious if there are downsides to this approach?
You can find tests for my suggested answer here: http://regexr.com/3e0lh
I have made this regex and solves the validation for dates as they come out of Javascript's .toISOString() method.
^[0-9]{4}-((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01])|(0[469]|11)-(0[1-9]|[12][0-9]|30)|(02)-(0[1-9]|[12][0-9]))T(0[0-9]|1[0-9]|2[0-3]):(0[0-9]|[1-5][0-9]):(0[0-9]|[1-5][0-9])\.[0-9]{3}Z$
Contemplated:
Proper symbols ('-', 'T', ':', '.', 'Z') in proper places.
Consistency with months of 29, 30 or 31 days.
Hours from 00 to 23.
Minutes and seconds from 00 to 59.
Milliseconds from 000 to 999.
Not contemplated:
Leap years.
Example date: 2019-11-15T13:34:22.178Z
Example to run directly in Chrome console: /^[0-9]{4}-((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01])|(0[469]|11)-(0[1-9]|[12][0-9]|30)|(02)-(0[1-9]|[12][0-9]))T(0[0-9]|1[0-9]|2[0-3]):(0[0-9]|[1-5][0-9]):(0[0-9]|[1-5][0-9])\.[0-9]{3}Z$/.test("2019-11-15T13:34:22.178Z");
Regex flow diagram (Regexper):
Here is a regular expression to check ISO 8601 date format including leap years and short-long months. To run this, you'll need to "ignore white-space". A compacted version without white-space is on regexlib: http://regexlib.com/REDetails.aspx?regexp_id=3344
There's more to ISO 8601 - this regex only cares for dates, but you can easily extend it to support time validation which is not that tricky.
Update: This works now with javascript (without lookbehinds)
^(?:
(?=
[02468][048]00
|[13579][26]00
|[0-9][0-9]0[48]
|[0-9][0-9][2468][048]
|[0-9][0-9][13579][26]
)
\d{4}
(?:
(-|)
(?:
(?:
00[1-9]
|0[1-9][0-9]
|[1-2][0-9][0-9]
|3[0-5][0-9]
|36[0-6]
)
|
(?:01|03|05|07|08|10|12)
(?:
\1
(?:0[1-9]|[12][0-9]|3[01])
)?
|
(?:04|06|09|11)
(?:
\1
(?:0[1-9]|[12][0-9]|30)
)?
|
02
(?:
\1
(?:0[1-9]|[12][0-9])
)?
|
W(?:0[1-9]|[1-4][0-9]|5[0-3])
(?:
\1
[1-7]
)?
)
)?
)$
|
^(?:
(?!
[02468][048]00
|[13579][26]00
|[0-9][0-9]0[48]
|[0-9][0-9][2468][048]
|[0-9][0-9][13579][26]
)
\d{4}
(?:
(-|)
(?:
(?:
00[1-9]
|0[1-9][0-9]
|[1-2][0-9][0-9]
|3[0-5][0-9]
|36[0-5]
)
|
(?:01|03|05|07|08|10|12)
(?:
\2
(?:0[1-9]|[12][0-9]|3[01])
)?
|
(?:04|06|09|11)
(?:
\2
(?:0[1-9]|[12][0-9]|30)
)?
|
(?:02)
(?:
\2
(?:0[1-9]|1[0-9]|2[0-8])
)?
|
W(?:0[1-9]|[1-4][0-9]|5[0-3])
(?:
\2
[1-7]
)?
)
)?
)$
To cater for time, add something like this to the mixture (from: http://underground.infovark.com/2008/07/22/iso-date-validation-regex/ ):
([T\s](([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)?(\15([0-5]\d))?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?
The ISO 8601 specification allows a wide variety of date formats. There's a mediocre explanation as to how to do it here. There is a fairly minor discrepancy between how Javascript's date input formatting and the ISO formatting for simple dates which do not specify timezones, and it can be easily mitigated using a string substitution. Fully supporting the ISO-8601 specification is non-trivial.
Here is a reference example which I do not guarantee to be complete, although it parses the non-duration dates from the aforementioned Wikipedia page.
Below is an example, and you can also see it's output on ideone. Unfortunately, it does not work to specification as it does not properly implement weeks. The definition of the week number 01 in ISO-8601 is non-trivial and requires some browsing the calendar to determine where week one begins, and what exactly it means in terms of the number of days in the specified year. This can probably be fairly easily corrected (I'm just tired of playing with it).
function parseISODate (input) {
var iso = /^(\d{4})(?:-?W(\d+)(?:-?(\d+)D?)?|(?:-(\d+))?-(\d+))(?:[T ](\d+):(\d+)(?::(\d+)(?:\.(\d+))?)?)?(?:Z(-?\d*))?$/;
var parts = input.match(iso);
if (parts == null) {
throw new Error("Invalid Date");
}
var year = Number(parts[1]);
if (typeof parts[2] != "undefined") {
/* Convert weeks to days, months 0 */
var weeks = Number(parts[2]) - 1;
var days = Number(parts[3]);
if (typeof days == "undefined") {
days = 0;
}
days += weeks * 7;
var months = 0;
}
else {
if (typeof parts[4] != "undefined") {
var months = Number(parts[4]) - 1;
}
else {
/* it's an ordinal date... */
var months = 0;
}
var days = Number(parts[5]);
}
if (typeof parts[6] != "undefined" &&
typeof parts[7] != "undefined")
{
var hours = Number(parts[6]);
var minutes = Number(parts[7]);
if (typeof parts[8] != "undefined") {
var seconds = Number(parts[8]);
if (typeof parts[9] != "undefined") {
var fractional = Number(parts[9]);
var milliseconds = fractional / 100;
}
else {
var milliseconds = 0
}
}
else {
var seconds = 0;
var milliseconds = 0;
}
}
else {
var hours = 0;
var minutes = 0;
var seconds = 0;
var fractional = 0;
var milliseconds = 0;
}
if (typeof parts[10] != "undefined") {
/* Timezone adjustment, offset the minutes appropriately */
var localzone = -(new Date().getTimezoneOffset());
var timezone = parts[10] * 60;
minutes = Number(minutes) + (timezone - localzone);
}
return new Date(year, months, days, hours, minutes, seconds, milliseconds);
}
print(parseISODate("2010-06-29T15:33:00Z-7"))
print(parseISODate("2010-06-29 06:14Z"))
print(parseISODate("2010-06-29T06:14Z"))
print(parseISODate("2010-06-29T06:14:30.2034Z"))
print(parseISODate("2010-W26-2"))
print(parseISODate("2010-180"))
yyyy-MM-dd
Too much explanation for most of the answers here, here's a short variation of #Sergey answer addressing some weird scenarios (like 2020-00-00), this RegExp only cares about the yyyy-MM-dd date:
// yyyy-MM-dd
^\d{4}-([0][1-9]|1[0-2])-([0-2][1-9]|[1-3]0|3[01])$
Also this one doesn't care about the number of days per month, like 2020-11-31 (because November has only 30 days).
My use-case was to convert a String into a Date (from an API param) and I needed only to know that the input string didn't contained strange stuff, I do the next validation against an actual Date object.
Here is my take on this:
^\d{4}-(?:0[1-9]|1[0-2])-(?:[0-2][1-9]|[1-3]0|3[01])T(?:[0-1][0-9]|2[0-3])(?::[0-6]\d)(?::[0-6]\d)?(?:\.\d{3})?(?:[+-][0-2]\d:[0-5]\d|Z)?$
Examples for a match:
2016-12-31T23:59:60+12:30
2021-05-10T09:05:12.000Z
3015-01-01T23:00+02:00
1001-01-31T23:59:59Z
2023-12-20T20:20
The minutes and seconds part could be refined more, but this is good enough for me.
Regexper
Not sure if it's relevant to the underlying problem you are trying to solve, but you can pass an ISO date string as a constructor arg to Date() and get an object out of it. The constructor is actually very flexible in terms of coercing a string into a Date.
with 02/29 validation from the year 1900 to 2999
(((2000|2400|2800|((19|2[0-9])(0[48]|[2468][048]|[13579][26])))-02-29)|(((19|2[0-9])[0-9]{2})-02-(0[1-9]|1[0-9]|2[0-8]))|(((19|2[0-9])[0-9]{2})-(0[13578]|10|12)-(0[1-9]|[12][0-9]|3[01]))|(((19|2[0-9])[0-9]{2})-(0[469]|11)-(0[1-9]|[12][0-9]|30)))T([01][0-9]|[2][0-3]):[0-5][0-9]:[0-5][0-9]\.[0-9]{3}Z
Brocks answers are good, but should start with ^ and end with $ so as not to allow prefix/suffix characters if all you are trying to match is the date string alone.
While using QRegExp with IsoDateWithMs the millisecond ones here did not work. instead the following saved the day.
\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d{1,3}
(I know this is a JS entry but it pops up first and would be helpful for c++ devs)