How to validate date with regular expression

Date Format (dd/mm/yyyy) Regular Expression Pattern

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

Description

(			#start of group #1
 0?[1-9]		#  01-09 or 1-9
 |                  	#  ..or
 [12][0-9]		#  10-19 or 20-29
 |			#  ..or
 3[01]			#  30, 31
) 			#end of group #1
  /			#  follow by a "/"
   (			#    start of group #2
    0?[1-9]		#	01-09 or 1-9
    |			#	..or
    1[012]		#	10,11,12
    )			#    end of group #2
     /			#	follow by a "/"
      (			#	  start of group #3
       (19|20)\\d\\d	#	    19[0-9][0-9] or 20[0-9][0-9]
       )		#	  end of group #3

The above regular expression is used to validate the date format in “dd/mm/yyyy”, you can easy customize to suit your need. However, it’s a bit hard to validate the leap year , 30 or 31 days of a month, we may need basic logic as below.

P.S Do let me know, if you know the regular expression which can check the leap and days of a month.

Java Regular Expression Example

package com.mkyong.regex;
 
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public class DateValidator{
 
  private Pattern pattern;
  private Matcher matcher;
 
  private static final String DATE_PATTERN = 
          "(0?[1-9]|[12][0-9]|3[01])/(0?[1-9]|1[012])/((19|20)\\d\\d)";
 
  public DateValidator(){
	  pattern = Pattern.compile(DATE_PATTERN);
  }
 
  /**
   * Validate date format with regular expression
   * @param date date address for validation
   * @return true valid date fromat, false invalid date format
   */
   public boolean validate(final String date){
 
     matcher = pattern.matcher(date);
 
     if(matcher.matches()){
 
	 matcher.reset();
 
	 if(matcher.find()){
 
             String day = matcher.group(1);
	     String month = matcher.group(2);
	     int year = Integer.parseInt(matcher.group(3));
 
	     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;
     }			    
   }
}

Date format that match:

1. “1/1/2010″ , “01/01/2020″
2. “31/1/2010″, “31/01/2020″
3. “29/2/2008″, “29/02/2008″
4. “28/2/2009″, “28/02/2009″
5. “31/3/2010″, “31/03/2010″
6. “30/4/2010″, “30/04/2010″
7. “31/5/2010″, “31/05/2010″
8. “30/6/2010″, “30/06/2010″
9. “31/7/2010″, “31/07/2010″
10. “31/8/2010″, “31/08/2010″
11. “30/9/2010″, “30/09/2010″
12. “31/10/2010″, “31/10/2010″
13. “30/11/2010″, “30/11/2010″
14. “31/12/2010″, “31/12/2010″

Date format doesn’t match:

1. “32/1/2010″ , “32/01/2020″ – day is out of range [1-31]
2. “1/13/2010″, “01/01/1820″ – month is out of range [1-12], year is out of range [1900-2999]
3. “29/2/2007″, “29/02/2007″ – 2007 is not leap year, only has 28 days
4. “30/2/2008″, “31/02/2008″ – leap year in February has 29 days only
5. “29/a/2008″, “a/02/2008″ – month is invalid, day is invalid
6. “333/2/2008″, “29/02/200a” – day is invalid, year is invalid
7. “31/4/20100″, “31/04/2010″ – April has 30 days only
8. “31/6/2010″, “31/06/2010″ -June has 30 days only
9. “31/9/2010″, “31/09/2010″ – September has 30 days only
10. “31/11/2010″ – November has 30 days only

Unit Test – DateValidatorTest

package com.mkyong.regex;
 
import org.testng.Assert;
import org.testng.annotations.*;
 
/**
 * Date format dd/mm/yyyy validator Testing
 * @author mkyong
 *
 */
public class DateValidatorTest {
 
	private DateValidator dateValidator;
 
	@BeforeClass
        public void initData(){
		dateValidator = new DateValidator();
        }
 
	@DataProvider
	public Object[][] ValidDateProvider() {
		return new Object[][]{
			new Object[] {"1/1/2010"}, new Object[] {"01/01/2020"}, 
			new Object[] {"31/1/2010"}, new Object[] {"31/01/2020"}, 
			new Object[] {"29/2/2008"}, new Object[] {"29/02/2008"},
			new Object[] {"28/2/2009"}, new Object[] {"28/02/2009"},
			new Object[] {"31/3/2010"}, new Object[] {"31/03/2010"},
			new Object[] {"30/4/2010"}, new Object[] {"30/04/2010"},
			new Object[] {"31/5/2010"}, new Object[] {"31/05/2010"},
			new Object[] {"30/6/2010"}, new Object[] {"30/06/2010"},
			new Object[] {"31/7/2010"}, new Object[] {"31/07/2010"},
			new Object[] {"31/8/2010"}, new Object[] {"31/08/2010"},
			new Object[] {"30/9/2010"}, new Object[] {"30/09/2010"},
			new Object[] {"31/10/2010"}, new Object[] {"31/10/2010"},
			new Object[] {"30/11/2010"}, new Object[] {"30/11/2010"},
			new Object[] {"31/12/2010"}, new Object[] {"31/12/2010"}
		};
	}
 
	@DataProvider
	public Object[][] InvalidDateProvider() {
		return new Object[][]{
			new Object[] {"32/1/2010"}, new Object[] {"32/01/2020"},
			new Object[] {"1/13/2010"}, new Object[] {"01/01/1820"},
			new Object[] {"29/2/2007"}, new Object[] {"29/02/2007"},
			new Object[] {"30/2/2008"}, new Object[] {"31/02/2008"},
			new Object[] {"29/a/2008"}, new Object[] {"a/02/2008"},
			new Object[] {"333/2/2008"}, new Object[] {"29/02/200a"},
			new Object[] {"31/4/2010"}, new Object[] {"31/04/2010"},
			new Object[] {"31/6/2010"}, new Object[] {"31/06/2010"},
			new Object[] {"31/9/2010"}, new Object[] {"31/09/2010"},
			new Object[] {"31/11/2010"}
		};
	}
 
	@Test(dataProvider = "ValidDateProvider")
	public void ValidDateTest(String date) {
		boolean valid = dateValidator.validate(date);
		System.out.println("Date is valid : " + date + " , " + valid);
		Assert.assertEquals(true, valid);
	}
 
	@Test(dataProvider = "InvalidDateProvider", 
                 dependsOnMethods="ValidDateTest")
	public void InValidDateTest(String date) {
		boolean valid = dateValidator.validate(date);
		System.out.println("Date is valid : " + date + " , " + valid);
		Assert.assertEquals(false, valid); 
	}
}

Unit Test – Result

[Parser] Running:
  E:\workspace\mkyong\temp-testng-customsuite.xml
 
Date is valid : 1/1/2010 , true
Date is valid : 01/01/2020 , true
Date is valid : 31/1/2010 , true
Date is valid : 31/01/2020 , true
Date is valid : 29/2/2008 , true
Date is valid : 29/02/2008 , true
Date is valid : 28/2/2009 , true
Date is valid : 28/02/2009 , true
Date is valid : 31/3/2010 , true
Date is valid : 31/03/2010 , true
Date is valid : 30/4/2010 , true
Date is valid : 30/04/2010 , true
Date is valid : 31/5/2010 , true
Date is valid : 31/05/2010 , true
Date is valid : 30/6/2010 , true
Date is valid : 30/06/2010 , true
Date is valid : 31/7/2010 , true
Date is valid : 31/07/2010 , true
Date is valid : 31/8/2010 , true
Date is valid : 31/08/2010 , true
Date is valid : 30/9/2010 , true
Date is valid : 30/09/2010 , true
Date is valid : 31/10/2010 , true
Date is valid : 31/10/2010 , true
Date is valid : 30/11/2010 , true
Date is valid : 30/11/2010 , true
Date is valid : 31/12/2010 , true
Date is valid : 31/12/2010 , true
Date is valid : 32/1/2010 , false
Date is valid : 32/01/2020 , false
Date is valid : 1/13/2010 , false
Date is valid : 01/01/1820 , false
Date is valid : 29/2/2007 , false
Date is valid : 29/02/2007 , false
Date is valid : 30/2/2008 , false
Date is valid : 31/02/2008 , false
Date is valid : 29/a/2008 , false
Date is valid : a/02/2008 , false
Date is valid : 333/2/2008 , false
Date is valid : 29/02/200a , false
Date is valid : 31/4/2010 , false
Date is valid : 31/04/2010 , false
Date is valid : 31/6/2010 , false
Date is valid : 31/06/2010 , false
Date is valid : 31/9/2010 , false
Date is valid : 31/09/2010 , false
Date is valid : 31/11/2010 , false
PASSED: ValidDateTest("1/1/2010")
PASSED: ValidDateTest("01/01/2020")
PASSED: ValidDateTest("31/1/2010")
PASSED: ValidDateTest("31/01/2020")
PASSED: ValidDateTest("29/2/2008")
PASSED: ValidDateTest("29/02/2008")
PASSED: ValidDateTest("28/2/2009")
PASSED: ValidDateTest("28/02/2009")
PASSED: ValidDateTest("31/3/2010")
PASSED: ValidDateTest("31/03/2010")
PASSED: ValidDateTest("30/4/2010")
PASSED: ValidDateTest("30/04/2010")
PASSED: ValidDateTest("31/5/2010")
PASSED: ValidDateTest("31/05/2010")
PASSED: ValidDateTest("30/6/2010")
PASSED: ValidDateTest("30/06/2010")
PASSED: ValidDateTest("31/7/2010")
PASSED: ValidDateTest("31/07/2010")
PASSED: ValidDateTest("31/8/2010")
PASSED: ValidDateTest("31/08/2010")
PASSED: ValidDateTest("30/9/2010")
PASSED: ValidDateTest("30/09/2010")
PASSED: ValidDateTest("31/10/2010")
PASSED: ValidDateTest("31/10/2010")
PASSED: ValidDateTest("30/11/2010")
PASSED: ValidDateTest("30/11/2010")
PASSED: ValidDateTest("31/12/2010")
PASSED: ValidDateTest("31/12/2010")
PASSED: InValidDateTest("32/1/2010")
PASSED: InValidDateTest("32/01/2020")
PASSED: InValidDateTest("1/13/2010")
PASSED: InValidDateTest("01/01/1820")
PASSED: InValidDateTest("29/2/2007")
PASSED: InValidDateTest("29/02/2007")
PASSED: InValidDateTest("30/2/2008")
PASSED: InValidDateTest("31/02/2008")
PASSED: InValidDateTest("29/a/2008")
PASSED: InValidDateTest("a/02/2008")
PASSED: InValidDateTest("333/2/2008")
PASSED: InValidDateTest("29/02/200a")
PASSED: InValidDateTest("31/4/2010")
PASSED: InValidDateTest("31/04/2010")
PASSED: InValidDateTest("31/6/2010")
PASSED: InValidDateTest("31/06/2010")
PASSED: InValidDateTest("31/9/2010")
PASSED: InValidDateTest("31/09/2010")
PASSED: InValidDateTest("31/11/2010")
 
===============================================
    com.mkyong.regex.DateValidatorTest
    Tests run: 47, Failures: 0, Skips: 0
===============================================
 
===============================================
mkyong
Total tests run: 47, Failures: 0, Skips: 0
===============================================

Want to learn more about regular expression? Highly recommend this best and classic book – “Mastering Regular Expression”



Tags :

About the Author

mkyong
Founder of Mkyong.com and HostingCompass.com, love Java and open source stuff. Follow him on Twitter, or befriend him on Facebook or Google Plus. If you like my tutorials, consider make a donation to these charities.

Comments

  • Pingback: water ionizer plans()

  • Pingback: Instagram volgers kopen()

  • Pingback: alkaline water benefits()

  • Pingback: stop parking()

  • Pingback: mobile porn movies()

  • Pingback: laan nu og her()

  • Pingback: hurtigt lan penge nu()

  • Pingback: stop parking()

  • Pingback: call tvpackages.net today()

  • Pingback: tv online, online tv()

  • Pingback: streaming movies()

  • Pingback: Blue Coaster33()

  • criptik

    I like your commented version of the regular expression but why not just compile that using Pattern.compile(DATE_PATTERN, Pattern.COMMENTS); ?
    instead of rewriting it?

  • Ralf

    Hi,

    I read this article and wanted to try and write a regex including 30/31 days and leap years (according to the article Despot posted). Haven’t tested the speed of it, but wanted to share the regex anyways.

    It’s testing dates in format DD-MM-YYYY (so from 01-01-0000 to 31-12-9999).

    ^(0[1-9]|1[0-9]|2[0-8]|29((?=-([0][13-9]|1[0-2])|(?=-(0[1-9]|1[0-2])-([0-9]{2}(0[48]|[13579][26]|[2468][048])|([02468][048]|[13579][26])00))))|30(?=-(0[13-9]|1[0-2]))|31(?=-(0[13578]|1[02])))-(0[1-9]|1[0-2])-[0-9]{4}$

    • Despot

      Hey Ralf,

      how about this one for the same purpose:
      ^(0?[1-9]|[12][0-9]|3[01])-(0?[1-9]|1[012])-(([^01][0-9]|19|[2-9][0-9])\d\d)$
      ?

      Cheers,
      Despot

      • Ralf

        Hey Despot,

        Wouldn’t your regex validate 31-04-2013 or 29-02-1900? My regex also checks if a month has 28, 29, 30 or 31 days.

        Greets, Ralf

        • Despot

          Ralf, true. Your code might test the boundaries (I haven’t checked it – it seems it does). Mine doesn’t.

          If you go for checking leap years you might run into a problem. Also it might be an issue if you use this for production its much slower than using a combination of simple regex + some custom code. Read the below comment (from me) for more on the matter.

          Cheers and happy coding ;)

  • Despot

    mkyong, your approach is ok, but has some flaws in it. The leap year calculation is not correct. 1900 is not a leap year (http://science.howstuffworks.com/science-vs-myth/everyday-myths/question50.htm). Also you are using too many if else statements. A switch in there would be better.

    I tested couple of approaches for speed and you can see the results here: http://stackoverflow.com/questions/2149680/regex-date-format-validation-on-java/18252071#18252071

  • http://www.quinqui.cl quinqui

    Thank you! It works great! :D

  • http://[email protected] [email protected]

    Excellent Job Yong…. You Blog is Very Usefull for developers as well as students…

  • Joan

    Awesome!
    Thanks

  • http://www.mygamegallery.com ravi

    I need to get the pattern of the given date String.
    please help me .

  • munnaf

    thank you. this is superb.

  • Diogene K.

    Thank you so much for your very helpful article. I like the way regexes help in validating data. The expression above will help me to derive some other ones to validate dates. Blessings to you from the Almighty.

  • Sandy

    Shouldn’t “^ and $” be used.I tried mentioned code and changed it for MM/DD/YYYY.But it was accepting 13/14 as valid date.Then I used “^ and $” as told at http://stackoverflow.com/questions/2137929/how-can-i-use-a-regular-expression-to-validate-month-input .And now its working as expected!!!!!!!

  • Arun.R.U

    Hi mkyong,

    How are you ? is it possible to make regular expression global ? I wanted to use xml validation in struts 2, but i am using same reguler expressions in all the xml so i wanted to make it global, do you have any idea about this ?

    Thanks….

  • Ryan

    I’m not really a Java dev, but I think I might have a slight improvement to John Smith’s answer. I do like his solution better than yours though simply because it’s easy to immediately understand what is going on. Your solution could be improved if you applied a Compose Method refactoring. :)

    public boolean dateValid(String d) {
    SimpleDateFormat sdf = new SimpleDateFormat(“M/d/yyyy”);
    try {
    sdf.setLenient(false);
    Date dx = sdf.parse(d);
    return true;
    } catch (ParseException e) {
    return false;
    }
    }

    • http://www.mkyong.com mkyong

      Thanks for sharing your code, may be you can further improve by using use static initializer for the SimpleDateFormat object.

      • http://www.geekswithblogs.net/ryanohs Ryan

        That’s a good idea. I also found a detailed answer on Stack Overflow about this.

        http://stackoverflow.com/questions/226910/how-to-sanity-check-a-date-in-java/892204#892204

        • http://www.mkyong.com mkyong

          Thanks for sharing it, it’s very informative and useful.

          • Ankit

            pattern=”(0?[1-9]|[12][0-9]|3[01])/(0?[1-9]|1[012])/((19|20)\\d\\d)”

            your pattern with 01/01/2001 date format not valid when i use in html5 input typ=”date” tag

  • Pingback: Java Regular Expression Tutorials | J2EE Web Development Tutorials()

  • Pingback: 10 Java Regular Expression Examples You Should Know | Regular Expressions()

  • http://Phi.Lho.free.fr PhiLho

    In a tutorial on regular expressions I wrote, at the end I show a RE validating dates, including leap years. Tutorial is: Regular Expressions: a simple, easy tutorial
    I haven’t invented the RE itself, but I improved it a bit, shortening it.
    As pointed out, often adding some procedural logic can goes a long way to avoid overly complex regexes… But hey, such exercise is a nice and entertaining way to improve the RE-fu…
    Beside, sometime we find ourself in the need to feed a validation logic with REs, without a way to add code. So it might be interesting to know how to handle these cases.
    That said, in an HTML forum having to validate dates, I used only a very primitive JavaScript RE, rejecting most blatant errors. I let the Java back-end to catch the corner cases and report them to the user…

  • mkyong

    it’s good to bring some discussion here :) , this example is created purely for demonstrate about how to use RegEx way to validate the a date.

    Not going to argue on the performance test, thanks for your contribution.

    The book “Java Puzzla” has a very good topic on the date validation in SimpleDateFormat , use static initializer for the SimpleDateFormat is much better than new object everytime.

  • http://arnulfo.net Franck Arnulfo

    A little precision, you can use a strict parsing with SimpleDateFormat by using sdf.setLenient(false) ( http://java.sun.com/j2se/1.4.2/docs/api/java/text/DateFormat.html#setLenient%28boolean%29 ).

  • John Smith

    I ran all your tests above 10,000 times using your code and 10,000 times using my code. Both finished in 3 seconds.

    Therefore, in 99.99999% of cases, my code is better than yours because it is effectively the same speed but much less code.

  • John Smith

    Prove it to me. Even if you validated a million dates, my way won’t take more than a second or two more than yours.

    In a real business application no one will notice the difference in speed of a few milliseconds per check.

  • John Smith

    All that code to validate a date? You don’t need anywhere near that much:

    public boolean dateValid(String d) {
    SimpleDateFormat sdf = new SimpleDateFormat(“M/d/yyyy”);

    try {
    Date dx = sdf.parse(d);
    return d.equals(sdf.format(dx));
    } catch (ParseException e) {
    return false;
    }
    }

    • mkyong

      Hi John,

      Thanks for it, your method is much more easy and straight forward, and most of the time i’m using your way as well :).

      However, the drawback is the new date object is expensive to create for validation, and RegEx is much more faster, if performance is one of your core consideration.

    • Despot

      This approach will not take care of dates like 0002/001/0003.
      Also this approach is slower (if that matters to you).