import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Example {
public static void main(String[] args) {
final String regex = "(?=(?:^(?:\\d\\d\\d\\d-(?:0[1-9]|10|11|12)-(?:0[1-9]|1[0-9]|2[0-8])|\\d\\d\\d\\d-(?:0[13-9]|10|11|12)-(?:29|30)|\\d\\d\\d\\d-(?:0[13578]|10|12)-31|(?:\\d\\d[2468][048]|\\d\\d0[48]|\\d\\d[13579][26])-02-29|(?:[02468][048]00|[13579][26]00)-02-29)T(?:(?:0[0-9]|1[0-9]|2[0-3]):(?:[0-5][0-9]):(?:[0-5][0-9]))(?:\\.\\d\\d\\d)?(?:Z|[\\+\\-](?:0[0-9]|1[012]):00|\\+0[34569]:30|\\+10:30|-0[39]:30|\\+1[34]:00|\\+0[58]:45|\\+12:45)$)|^(?:1972|198[1235]|199[2347]|2012|2015)-06-30T23:59:60Z$|^(?:197[2-9]|1987|1989|199[058]|2005|2008|2016)-12-31T23:59:60Z$)(?!.*-00:00$)^(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)T(\\d\\d):(\\d\\d):(\\d\\d)(?:\\.(\\d\\d\\d))?((Z)|([\\+\\-])(\\d\\d):(\\d\\d))$";
final String string = "Strong Matcher for ISO 8601 / RFC 3339 Date Times; rejects bad TZ offsets, illegal times (Museum of Bad Data)\n"
+ "See below for expanded matcher\n\n"
+ "```\n"
+ "// accept: Exemplars\n"
+ "2008-02-03T04:05:06.007Z\n"
+ "2008-02-03T04:05:06Z\n"
+ "0000-01-01T00:00:00.000Z\n"
+ "0000-02-29T04:05:06.007Z\n"
+ "9999-12-31T23:59:59.999Z\n"
+ "9999-12-31T23:59:59Z\n"
+ "2008-02-03T04:05:06.007+12:45\n"
+ "2008-02-03T04:05:06+03:30\n"
+ "0000-01-01T00:00:00.007-09:30\n"
+ "0000-02-29T04:05:06.007+14:00\n"
+ "9999-12-31T23:59:59.999+12:00\n"
+ "9999-12-31T23:59:59-12:00\n"
+ "// accept: Leap day, year is multiple of four\n"
+ "0004-02-29T04:05:06.007Z\n"
+ "0008-02-29T04:05:06.007Z\n"
+ "0012-02-29T04:05:06.007Z\n"
+ "0016-02-29T04:05:06.007Z\n"
+ "0020-02-29T04:05:06.007Z\n"
+ "0024-02-29T04:05:06.007Z\n"
+ "0028-02-29T04:05:06.007Z\n"
+ "0032-02-29T04:05:06.007Z\n"
+ "0036-02-29T04:05:06.007Z\n"
+ "0040-02-29T04:05:06.007Z\n"
+ "0044-02-29T04:05:06.007Z\n"
+ "0048-02-29T04:05:06.007Z\n"
+ "0052-02-29T04:05:06.007Z\n"
+ "0056-02-29T04:05:06.007Z\n"
+ "0060-02-29T04:05:06.007Z\n"
+ "0064-02-29T04:05:06.007Z\n"
+ "0068-02-29T04:05:06.007Z\n"
+ "0072-02-29T04:05:06.007Z\n"
+ "0076-02-29T04:05:06.007Z\n"
+ "0080-02-29T04:05:06.007Z\n"
+ "0084-02-29T04:05:06.007Z\n"
+ "0088-02-29T04:05:06.007Z\n"
+ "0092-02-29T04:05:06.007Z\n"
+ "0096-02-29T04:05:06.007Z\n"
+ "1560-02-29T04:05:06.007Z\n"
+ "2004-02-29T04:05:06.007Z\n"
+ "2008-02-29T04:05:06.007Z\n"
+ "2012-02-29T04:05:06.007Z\n"
+ "2016-02-29T04:05:06.007Z\n"
+ "2020-02-29T04:05:06.007Z\n"
+ "2024-02-29T04:05:06.007Z\n"
+ "2028-02-29T04:05:06.007Z\n"
+ "2032-02-29T04:05:06.007Z\n"
+ "2036-02-29T04:05:06.007Z\n"
+ "2040-02-29T04:05:06.007Z\n"
+ "2044-02-29T04:05:06.007Z\n"
+ "9996-02-29T04:05:06.007Z\n"
+ "// accept: Leap day, year is Multiple of 400\n"
+ "0000-02-29T04:05:06.007Z\n"
+ "0400-02-29T04:05:06.007Z\n"
+ "0800-02-29T04:05:06.007Z\n"
+ "1200-02-29T04:05:06.007Z\n"
+ "1600-02-29T04:05:06.007Z\n"
+ "2000-02-29T04:05:06.007Z\n"
+ "2400-02-29T04:05:06.007Z\n"
+ "2800-02-29T04:05:06.007Z\n"
+ "3200-02-29T04:05:06.007Z\n"
+ "3600-02-29T04:05:06.007Z\n"
+ "4000-02-29T04:05:06.007Z\n"
+ "4400-02-29T04:05:06.007Z\n"
+ "4800-02-29T04:05:06.007Z\n"
+ "5200-02-29T04:05:06.007Z\n"
+ "5600-02-29T04:05:06.007Z\n"
+ "6000-02-29T04:05:06.007Z\n"
+ "6400-02-29T04:05:06.007Z\n"
+ "6800-02-29T04:05:06.007Z\n"
+ "7200-02-29T04:05:06.007Z\n"
+ "7600-02-29T04:05:06.007Z\n"
+ "8000-02-29T04:05:06.007Z\n"
+ "8400-02-29T04:05:06.007Z\n"
+ "8800-02-29T04:05:06.007Z\n"
+ "9200-02-29T04:05:06.007Z\n"
+ "9600-02-29T04:05:06.007Z\n"
+ "// accept: Day in range for month\n"
+ "2008-01-30T04:05:06.007Z\n"
+ "2008-03-30T04:05:06.007Z\n"
+ "2008-04-30T04:05:06.007Z\n"
+ "2008-05-30T04:05:06.007Z\n"
+ "2008-06-30T04:05:06.007Z\n"
+ "2008-07-30T04:05:06.007Z\n"
+ "2008-08-30T04:05:06.007Z\n"
+ "2008-09-30T04:05:06.007Z\n"
+ "2008-10-30T04:05:06.007Z\n"
+ "2008-11-30T04:05:06.007Z\n"
+ "2008-12-30T04:05:06.007Z\n"
+ "2008-01-31T04:05:06.007Z\n"
+ "2008-03-31T04:05:06.007Z\n"
+ "2008-05-31T04:05:06.007Z\n"
+ "2008-07-31T04:05:06.007Z\n"
+ "2008-08-31T04:05:06.007Z\n"
+ "2008-10-31T04:05:06.007Z\n"
+ "2008-12-31T04:05:06.007Z\n"
+ "// accept: had leap second\n"
+ "1972-06-30T23:59:60Z\n"
+ "1981-06-30T23:59:60Z\n"
+ "1982-06-30T23:59:60Z\n"
+ "1983-06-30T23:59:60Z\n"
+ "1985-06-30T23:59:60Z\n"
+ "1992-06-30T23:59:60Z\n"
+ "1993-06-30T23:59:60Z\n"
+ "1994-06-30T23:59:60Z\n"
+ "1997-06-30T23:59:60Z\n"
+ "2012-06-30T23:59:60Z\n"
+ "2015-06-30T23:59:60Z\n"
+ "1972-12-31T23:59:60Z\n"
+ "1973-12-31T23:59:60Z\n"
+ "1974-12-31T23:59:60Z\n"
+ "1975-12-31T23:59:60Z\n"
+ "1976-12-31T23:59:60Z\n"
+ "1977-12-31T23:59:60Z\n"
+ "1978-12-31T23:59:60Z\n"
+ "1979-12-31T23:59:60Z\n"
+ "1987-12-31T23:59:60Z\n"
+ "1989-12-31T23:59:60Z\n"
+ "1990-12-31T23:59:60Z\n"
+ "1995-12-31T23:59:60Z\n"
+ "1998-12-31T23:59:60Z\n"
+ "2005-12-31T23:59:60Z\n"
+ "2008-12-31T23:59:60Z\n"
+ "2016-12-31T23:59:60Z\n"
+ "// REJECT: Year out of range\n"
+ "10000-02-29T04:05:06.007Z\n"
+ "// REJECT: Month out of range\n"
+ "2008-00-30T04:05:06.007Z\n"
+ "2008-13-30T04:05:06.007Z\n"
+ "2008-14-30T04:05:06.007Z\n"
+ "2008-20-30T04:05:06.007Z\n"
+ "// REJECT: Day out of range for month\n"
+ "2008-02-30T04:05:06.007Z\n"
+ "2008-04-31T04:05:06.007Z\n"
+ "2008-06-31T04:05:06.007Z\n"
+ "2008-09-31T04:05:06.007Z\n"
+ "2008-11-31T04:05:06.007Z\n"
+ "2008-02-31T04:05:06.007Z\n"
+ "// REJECT: Day out of range\n"
+ "2008-12-32T04:05:06.007Z\n"
+ "2008-12-99T04:05:06.007Z\n"
+ "2008-12-00T04:05:06.007Z\n"
+ "// REJECT: Hour out of range\n"
+ "2008-12-08T60:05:06.007Z\n"
+ "2008-12-08T99:05:06.007Z\n"
+ "// REJECT: Minute out of range\n"
+ "2008-12-08T04:60:06.007Z\n"
+ "2008-12-08T04:99:06.007Z\n"
+ "// REJECT: Seconds out of range\n"
+ "9999-12-31T59:59:61.999Z\n"
+ "2008-02-03T04:05:61.999Z\n"
+ "2008-02-03T04:05:61Z\n"
+ "// REJECT: Negative dates not accepted\n"
+ "-2000-02-29T04:05:06.007Z\n"
+ "-0400-02-29T04:05:06.007Z\n"
+ "-0100-02-29T04:05:06.007Z\n"
+ "-0004-02-29T04:05:06.007Z\n"
+ "// REJECT: stray characters\n"
+ " 2008-12-31T04:05:06.007Z\n"
+ "2008-12-31T04:05:06.007Z \n"
+ "2008-12-31T04:05:06.007 Z\n"
+ "// REJECT: Malformed\n"
+ "2008-02-0304:05:06.007Z\n"
+ "20080203T040506.007Z\n"
+ "2008-02-03T04:05:06007Z\n"
+ "2008-02-03T04:05:06.7Z\n"
+ "2008-02-03T04:05:06.07Z\n"
+ "2008-02-03T04:05:06.0007Z\n"
+ "2008-02-03T04:05:06\n"
+ "2008-02-03T04:05:06.Z\n"
+ "// REJECT: no leap second\n"
+ "1973-06-30T23:59:60Z\n"
+ "1974-06-30T23:59:60Z\n"
+ "1975-06-30T23:59:60Z\n"
+ "1976-06-30T23:59:60Z\n"
+ "1977-06-30T23:59:60Z\n"
+ "1978-06-30T23:59:60Z\n"
+ "1979-06-30T23:59:60Z\n"
+ "1980-06-30T23:59:60Z\n"
+ "1984-06-30T23:59:60Z\n"
+ "1986-06-30T23:59:60Z\n"
+ "1987-06-30T23:59:60Z\n"
+ "1988-06-30T23:59:60Z\n"
+ "1989-06-30T23:59:60Z\n"
+ "1990-06-30T23:59:60Z\n"
+ "1991-06-30T23:59:60Z\n"
+ "1995-06-30T23:59:60Z\n"
+ "1996-06-30T23:59:60Z\n"
+ "1998-06-30T23:59:60Z\n"
+ "1999-06-30T23:59:60Z\n"
+ "2000-06-30T23:59:60Z\n"
+ "2001-06-30T23:59:60Z\n"
+ "2002-06-30T23:59:60Z\n"
+ "2003-06-30T23:59:60Z\n"
+ "2004-06-30T23:59:60Z\n"
+ "2005-06-30T23:59:60Z\n"
+ "2006-06-30T23:59:60Z\n"
+ "2007-06-30T23:59:60Z\n"
+ "2008-06-30T23:59:60Z\n"
+ "2009-06-30T23:59:60Z\n"
+ "2010-06-30T23:59:60Z\n"
+ "2011-06-30T23:59:60Z\n"
+ "2013-06-30T23:59:60Z\n"
+ "2014-06-30T23:59:60Z\n"
+ "2016-06-30T23:59:60Z\n"
+ "2017-06-30T23:59:60Z\n"
+ "2018-06-30T23:59:60Z\n"
+ "2019-06-30T23:59:60Z\n"
+ "2020-06-30T23:59:60Z\n"
+ "2021-06-30T23:59:60Z\n"
+ "2022-06-30T23:59:60Z\n"
+ "2023-06-30T23:59:60Z\n"
+ "1980-12-31T23:59:60Z\n"
+ "1981-12-31T23:59:60Z\n"
+ "1982-12-31T23:59:60Z\n"
+ "1983-12-31T23:59:60Z\n"
+ "1984-12-31T23:59:60Z\n"
+ "1985-12-31T23:59:60Z\n"
+ "1986-12-31T23:59:60Z\n"
+ "1988-12-31T23:59:60Z\n"
+ "1991-12-31T23:59:60Z\n"
+ "1992-12-31T23:59:60Z\n"
+ "1993-12-31T23:59:60Z\n"
+ "1994-12-31T23:59:60Z\n"
+ "1996-12-31T23:59:60Z\n"
+ "1997-12-31T23:59:60Z\n"
+ "1999-12-31T23:59:60Z\n"
+ "2000-12-31T23:59:60Z\n"
+ "2001-12-31T23:59:60Z\n"
+ "2002-12-31T23:59:60Z\n"
+ "2003-12-31T23:59:60Z\n"
+ "2004-12-31T23:59:60Z\n"
+ "2006-12-31T23:59:60Z\n"
+ "2007-12-31T23:59:60Z\n"
+ "2009-12-31T23:59:60Z\n"
+ "2010-12-31T23:59:60Z\n"
+ "2011-12-31T23:59:60Z\n"
+ "2012-12-31T23:59:60Z\n"
+ "2013-12-31T23:59:60Z\n"
+ "2014-12-31T23:59:60Z\n"
+ "2015-12-31T23:59:60Z\n"
+ "2017-12-31T23:59:60Z\n"
+ "2018-12-31T23:59:60Z\n"
+ "2019-12-31T23:59:60Z\n"
+ "2020-12-31T23:59:60Z\n"
+ "2021-12-31T23:59:60Z\n"
+ "2022-12-31T23:59:60Z\n"
+ "2023-12-31T23:59:60Z\n"
+ "// REJECT: assumes no future leap seconds\n"
+ "2024-12-31T23:59:60Z\n"
+ "2099-12-31T23:59:60Z\n"
+ "9999-12-31T23:59:60Z\n"
+ "// REJECT: leap seconds only in UTC format\n"
+ "2005-12-31T23:59:60+00:00\n"
+ "2008-12-31T23:59:60+00:00\n"
+ "// REJECT: Not a leap day, year is not a multiple of four\n"
+ "0101-02-29T04:05:06.007Z\n"
+ "0102-02-29T04:05:06.007Z\n"
+ "0103-02-29T04:05:06.007Z\n"
+ "1537-02-29T04:05:06.007Z\n"
+ "1538-02-29T04:05:06.007Z\n"
+ "2001-02-29T04:05:06.007Z\n"
+ "2002-02-29T04:05:06.007Z\n"
+ "2003-02-29T04:05:06.007Z\n"
+ "2021-02-29T04:05:06.007Z\n"
+ "2022-02-29T04:05:06.007Z\n"
+ "2023-02-29T04:05:06.007Z\n"
+ "2025-02-29T04:05:06.007Z\n"
+ "2026-02-29T04:05:06.007Z\n"
+ "2027-02-29T04:05:06.007Z\n"
+ "2029-02-29T04:05:06.007Z\n"
+ "2030-02-29T04:05:06.007Z\n"
+ "2031-02-29T04:05:06.007Z\n"
+ "2033-02-29T04:05:06.007Z\n"
+ "2034-02-29T04:05:06.007Z\n"
+ "2035-02-29T04:05:06.007Z\n"
+ "2037-02-29T04:05:06.007Z\n"
+ "2038-02-29T04:05:06.007Z\n"
+ "2039-02-29T04:05:06.007Z\n"
+ "2041-02-29T04:05:06.007Z\n"
+ "2042-02-29T04:05:06.007Z\n"
+ "2043-02-29T04:05:06.007Z\n"
+ "9997-02-29T04:05:06.007Z\n"
+ "9998-02-29T04:05:06.007Z\n"
+ "9999-02-29T04:05:06.007Z\n"
+ "// REJECT: Not a leap day, year is a multiple of 100 but not 400\n"
+ "0100-02-29T04:05:06.007Z\n"
+ "0200-02-29T04:05:06.007Z\n"
+ "0300-02-29T04:05:06.007Z\n"
+ "0500-02-29T04:05:06.007Z\n"
+ "0600-02-29T04:05:06.007Z\n"
+ "0700-02-29T04:05:06.007Z\n"
+ "0900-02-29T04:05:06.007Z\n"
+ "1000-02-29T04:05:06.007Z\n"
+ "1100-02-29T04:05:06.007Z\n"
+ "1500-02-29T04:05:06.007Z\n"
+ "2100-02-29T04:05:06.007Z\n"
+ "2200-02-29T04:05:06.007Z\n"
+ "2300-02-29T04:05:06.007Z\n"
+ "2500-02-29T04:05:06.007Z\n"
+ "2600-02-29T04:05:06.007Z\n"
+ "2700-02-29T04:05:06.007Z\n"
+ "2900-02-29T04:05:06.007Z\n"
+ "3000-02-29T04:05:06.007Z\n"
+ "3100-02-29T04:05:06.007Z\n"
+ "3300-02-29T04:05:06.007Z\n"
+ "3400-02-29T04:05:06.007Z\n"
+ "3500-02-29T04:05:06.007Z\n"
+ "3700-02-29T04:05:06.007Z\n"
+ "```\n\n"
+ "```\n"
+ "(?=\n"
+ " (?:^\n"
+ " (?: # All non-leap-second YYYY-MM-DD parts:\n"
+ " (?:\\d\\d\\d\\d-(?:0[1-9] |10|11|12)-(?:0[1-9]|1[0-9]|2[0-8])) # Days 01-28\n"
+ " | (?:\\d\\d\\d\\d-(?:0[13-9] |10|11|12)-(29|30)) # Days 29+30\n"
+ " | (?:\\d\\d\\d\\d-(?:0[13578]|10 |12)-31) # Day 31\n"
+ " | (?:\\d\\d[2468][048]|\\d\\d0[48]|\\d\\d[13579][26])-02-29 # leap years not divisible by 100\n"
+ " | (?:[02468][048]00|[13579][26]00)-02-29 # leap years divisible by 400\n"
+ " )\n"
+ " T\n"
+ " (?:(?:0[0-9]|1[0-9]|2[0-3]):(?:[0-5][0-9]):(?:[0-5][0-9])) # time part\n"
+ " (?:\\.\\d\\d\\d)? # ms part (optional)\n"
+ " (?:Z|[\\+\\-](?:0[0-9]|1[012]):00|\\+0[34569]:30|\\+10:30|-0[39]:30|\\+1[34]:00|\\+0[58]:45|\\+12:45)\n"
+ " $)\n"
+ " |^(?:1972 |198[1235]|199[2347]|2012|2015 )-06-30T23:59:60Z$ # all june leapsecs\n"
+ " |^(?:197[2-9]|1987|1989|199[058] |2005|2008|2016)-12-31T23:59:60Z$ # all december leapsecs\n"
+ ")\n"
+ "(?!.*-00:00$) # if given a -00:00 offset reject unconditionally, psychhhh\n"
+ "# OK! Since only valid times are now possible, we can use a loose pattern match to parse.\n"
+ "^(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)T(\\d\\d):(\\d\\d):(\\d\\d)(?:\\.(\\d\\d\\d))?((Z)|([\\+\\-])(\\d\\d):(\\d\\d))$\n"
+ "```";
final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
final Matcher matcher = pattern.matcher(string);
while (matcher.find()) {
System.out.println("Full match: " + matcher.group(0));
for (int i = 1; i <= matcher.groupCount(); i++) {
System.out.println("Group " + i + ": " + matcher.group(i));
}
}
}
}
Please keep in mind that these code samples are automatically generated and are not guaranteed to work. If you find any syntax errors, feel free to submit a bug report. For a full regex reference for Java, please visit: https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html