[regex] Regex to validate date format dd/mm/yyyy

I need to validate a date string for the format dd/mm/yyyy with a regular expresssion.

This regex validates dd/mm/yyyy, but not the invalid dates like 31/02/4500:

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

What is a valid regex to validate dd/mm/yyyy format with leap year support?

This question is related to regex

The answer is


Please Following Expression

Regex regex = new Regex(@"(((0|1)[0-9]|2[0-9]|3[0-1])\/(0[1-9]|1[0-2])\/((19|20)\d\d))$");

try this.

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

you can test regular expression at http://www.regular-expressions.info/javascriptexample.html easily.


For those who look at these and get completely confused, here is an excerpt from my script. Unfortunately, all it does is match valid numbers in a date time input, and 31st Feb will be marked as valid, but as so many have said, regex really isn't the best tool to do this test.

To match a date in the format 'yyyy-MM-dd hh:mm' (Or indeed in whatever order you please)

var dateerrors = false;
var yearReg = '(201[4-9]|202[0-9])';            ///< Allows a number between 2014 and 2029
var monthReg = '(0[1-9]|1[0-2])';               ///< Allows a number between 00 and 12
var dayReg = '(0[1-9]|1[0-9]|2[0-9]|3[0-1])';   ///< Allows a number between 00 and 31
var hourReg = '([0-1][0-9]|2[0-3])';            ///< Allows a number between 00 and 24
var minReg = '([0-5][0-9])';                    ///< Allows a number between 00 and 59
var reg = new RegExp('^' + yearReg + '-' + monthReg + '-' + dayReg + ' ' + hourReg + ':' + minReg + '$', 'g');
$('input').filter(function () {return this.id.match(/myhtml_element_with_id_\d+_datetime/);}).each(function (e) {
    if (e > 0) {
        // Don't test the first input. This will use the default
        var val = $(this).val();
        if (val && !val.trim().match(reg)) {
            dateerrors = true;
            return false;
        }
    }
});
if (dateerrors) {
    alert('You must enter a validate date in the format "yyyy-mm-dd HH:MM", e.g. 2019-12-31 19:30');
    return false;
}

The above script starts off by building a regex object. It then finds all of the inputs whose id's match a certain pattern and then loops through these. I don't test the first input I find (if (e > 0)).

A bit of explanation:

var reg = new RegExp('^' + yearReg + '-' + monthReg + '-' + dayReg + ' ' + hourReg + ':' + minReg + '$', 'g');

^ means start of match, whereas $ means end of match.

return this.id.match(/myhtml_element_with_id_\d+_datetime/);

\d+ means match a single or a contiguous sequence of integers, so myhtml_element_with_id_56_datetime and myhtml_element_with_id_2_datetime will match, but myhtml_element_with_id_5a_datetime will not


Here is another version of regex to match any of the following date formats and allow leading zeros to be omitted:

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

Matches:

1/1/11 or 1.1.11 or 1-1-11 : true 01/01/11 or 01.01.11 or 01-01-11 : true 01/01/2011 or 01.01.2011 or 01-01-2011 : true 01/1/2011 or 01.1.2011 or 01-1-2011 : true 1/11/2011 or 1.11.2011 or 1-11-2011 : true 1/11/11 or 1.11.11 or 1-11-11 : true 11/1/11 or 11.1.11 or 11-1-11 : true

Regular expression visualization

Debuggex Demo


Here I wrote one for dd/mm/yyyy where separator can be one of -.,/ year range 0000-9999.

It deals with leap years and is designed for regex flavors, that support lookaheads, capturing groups and backreferences. NOT valid for such as d/m/yyyy. If needed add further separators to [-.,/]

^(?=\d{2}([-.,\/])\d{2}\1\d{4}$)(?:0[1-9]|1\d|[2][0-8]|29(?!.02.(?!(?!(?:[02468][1-35-79]|[13579][0-13-57-9])00)\d{2}(?:[02468][048]|[13579][26])))|30(?!.02)|31(?=.(?:0[13578]|10|12))).(?:0[1-9]|1[012]).\d{4}$

Test at regex101; as a Java string:

"^(?=\\d{2}([-.,\\/])\\d{2}\\1\\d{4}$)(?:0[1-9]|1\\d|[2][0-8]|29(?!.02.(?!(?!(?:[02468][1-35-79]|[13579][0-13-57-9])00)\\d{2}(?:[02468][048]|[13579][26])))|30(?!.02)|31(?=.(?:0[13578]|10|12))).(?:0[1-9]|1[012]).\\d{4}$"

explained:

(?x) # modifier x: free spacing mode (for comments)
     # verify date dd/mm/yyyy; possible separators: -.,/
     # valid year range: 0000-9999

^    # start anchor

# precheck xx-xx-xxxx,... add new separators here
(?=\d{2}([-.,\/])\d{2}\1\d{4}$)

(?:  # day-check: non caturing group

  # days 01-28
  0[1-9]|1\d|[2][0-8]| 

  # february 29d check for leap year: all 4y / 00 years: only each 400
  # 0400,0800,1200,1600,2000,...
  29
  (?!.02. # not if feb: if not ...
    (?!
      # 00 years: exclude !0 %400 years
      (?!(?:[02468][1-35-79]|[13579][0-13-57-9])00)

      # 00,04,08,12,... 
      \d{2}(?:[02468][048]|[13579][26])
    )
  )|

  # d30 negative lookahead: february cannot have 30 days
  30(?!.02)|

  # d31 positive lookahead: month up to 31 days
  31(?=.(?:0[13578]|10|12))

) # eof day-check

# month 01-12
.(?:0[1-9]|1[012])

# year 0000-9999
.\d{4}

$ # end anchor

Also see SO Regex FAQ; Please let me know, if it fails.


Found this reg ex here

^(((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])|((16|[2468][048]|[3579][26])00))))$

This validates the format mm/dd/yyyy and valid dates correctly (but not m/d/yyyy).

Some tests


In case you are looking for specific format, This works fine for "dd/MM/yyyy" & "dd/MMM/yyyy" date format only based on Alok answer.

function isValidDateFormatDDMMYYYY(inputDate) {
    var date_regex = /^(?:(?:31(\/)(?:0?[13578]|1[02]|(?:Jan|Mar|May|Jul|Aug|Oct|Dec)))\1|(?:(?:29|30)(\/)(?:0?[1,3-9]|1[0-2]|(?:Jan|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec))\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:29(\/)(?:0?2|(?:Feb))\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\d|2[0-8])(\/)(?:(?:0?[1-9]|(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep))|(?:1[0-2]|(?:Oct|Nov|Dec)))\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$/;
    return date_regex.test(inputDate);
}

Few examples working thru this code -

  • isValidDateFormatDDMMYYYY("15/01/1999") // returns True
  • isValidDateFormatDDMMYYYY("15/Jan/1999") // returns True
  • isValidDateFormatDDMMYYYY("15/1/1999") // returns True
  • isValidDateFormatDDMMYYYY("1/15/1999") // returns False

Thanks


The following expression is nice and easy to manipulate:

((((0[13578]|1[02])(\/|-|.)(0[1-9]|1[0-9]|2[0-9]|3[01]))|((0[469]|11)(\/|-|.)(0[1-9]|1[0-9]|2[0-9]|3[0]))|((02)((\/|-|.)(0[1-9]|1[0-9]|2[0-8]))))(\/|-|.)(19([6-9][0-9])|20(0[0-9]|1[0-4])))|((02)(\/|-|.)(29)(\/|-|.)(19(6[048]|7[26]|8[048]|9[26])|20(0[048]|1[26])))

It validates according to the MM/dd/YYYY format and allows for leap year support from 1960 to 2016. If you need the leap year support extended you need only manipulate this part of the expression:

(19(6[048]|7[26]|8[048]|9[26])|20(0[048]|1[26]))

Hope this helped you a lot


import re
expression = "Nov 05 20:10:09 2020"
reg_ex = r'((Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ([0-2][0-9]|(3)[0-1]) (([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])) (\d{4}))'
assert re.fullmatch(reg_ex, expression), True

Expaination with respect to given Example

  • Nov = A group of possible months i.e. (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)
  • 05 = A group of valid days i.e. ([0-2][0-9]|(3)[0-1])
  • 20:10:09 = A group for getting valid Hours : ([0-1][0-9]|2[0-3]), Minutes : ([0-5][0-9]) and Seconds : ([0-5][0-9])
  • 2020 = A group for getting year i.e (\d{4}))

Notice:

Your regexp does not work for years that "are multiples of 4 and 100, but not of 400". Years that pass that test are not leap years. For example: 1900, 2100, 2200, 2300, 2500, etc. In other words, it puts all years with the format \d\d00 in the same class of leap years, which is incorrect. – MuchToLearn

So it works properly only for [1901 - 2099] (Whew)

dd/MM/yyyy:

Checks if leap year. Years from 1900 to 9999 are valid. Only dd/MM/yyyy

(^(((0[1-9]|1[0-9]|2[0-8])[\/](0[1-9]|1[012]))|((29|30|31)[\/](0[13578]|1[02]))|((29|30)[\/](0[4,6,9]|11)))[\/](19|[2-9][0-9])\d\d$)|(^29[\/]02[\/](19|[2-9][0-9])(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)$)

The best way according to me is to use the Moment.js isValid() method by specifying the format and use strict parsing.

As moment.js documentation says

As of version 2.3.0, you may specify a boolean for the last argument to make Moment use strict parsing. Strict parsing requires that the format and input match exactly, including delimiters.

value = '2020-05-25';
format = 'YYYY-MM-DD';
moment(value, format, true).isValid() // true

I suspect that the following is as accurate as can be expected without knowing when the user's locale switched over from the Julian to the Gregorian calendars.

It accepts either '-', '/', or nothing as separators between year, month, and day, no matter the order.

MMddyyyy:

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

ddMMyyyy:

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

yyyyMMdd:

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

Other than order, these all are accurate to the Julian Calendar (leap year every four years) until 1700, when the Gregorian Calendar diverges from the Julian. It has two issues:

  1. It accepts the year 0000, which doesn't exist in many, but not all, standards. Note that ISO 8601 does accept year 0000 (equivalent to 1 BCE).
  2. It doesn't skip the 10-13 days which were lost when the Gregorian Calendar came into use. This varies by locality though. For example, the Roman Catholic Church skipped 10 days, October 5th through October 14th, 1582, but Greece (the last to switch) skipped February 16th through the 28th of 1923, 13 days, having to take into account the leap years of 1700, 1800, and 1900.

This has been tested against Java's calendar implementation from the year 0001 until the year 9999 with the only discrepancy being the abovementioned 10 days in 1582.


For use only for the day:

<input placeholder="day" maxlength="2" minlength="1" formControlName="birthDay" 
   name="birthDay"pattern="(0[1-9]|1[0-9]|2[0-9]|3[0-1])" >/

For use only for the month:

 <input placeholder="month" maxlength="2" minlength="1" 
  formControlName="month" name="month" formControlName="month" name="month" pattern="(0[1- 
  9]|1[0-2])">/

For date MM/DD/YYYY you can use

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

It verify proper days and moths.

Remeber that you can check your regular expression at

regex101

which i recommend :)

Have fun!


Further extended the regex given by @AlokChaudhary to support:

1. dd mmm YYYY (in addition to dd-mmm-YYYY, dd/mmm/YYYY, dd.mmm.YYYY).

2. mmm in all CAPITAL LETTERS format (in addition to Title format)

dd mmm YYYY e.g. 30 Apr 2026 or 24 DEC 2028 are popular.

Extended regex:

(^(?:(?:(?:31(?:(?:([-.\/])(?:0?[13578]|1[02])\1)|(?:([-.\/ ])(?:Jan|JAN|Mar|MAR|May|MAY|Jul|JUL|Aug|AUG|Oct|OCT|Dec|DEC)\2)))|(?:(?:29|30)(?:(?:([-.\/])(?:0?[13-9]|1[0-2])\3)|(?:([-.\/ ])(?:Jan|JAN|Mar|MAR|Apr|APR|May|MAY|Jun|JUN|Jul|JUL|Aug|AUG|Sep|SEP|Oct|OCT|Nov|NOV|Dec|DEC)\4))))(?:(?:1[6-9]|[2-9]\d)?\d{2}))$|^(?:29(?:(?:([-.\/])(?:0?2)\5)|(?:([-.\/ ])(?:Feb|FEB)\6))(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00)))$|^(?:(?:0?[1-9]|1\d|2[0-8])(?:(?:([-.\/])(?:(?:0?[1-9]|(?:1[0-2])))\7)|(?:([-.\/ ])(?:Jan|JAN|Feb|FEB|Mar|MAR|May|MAY|Jul|JUL|Aug|AUG|Oct|OCT|Dec|DEC)\8))(?:(?:1[6-9]|[2-9]\d)?\d{2}))$)

Test cases included in the Regex Demo

Features (retained):

  • Leap year checking (Feb 29 validation) includes the logics: (divisible by 4 but not divisible by 100) or (divisible by 400)
  • Supports years 1600 ~ 9999
  • Supports dd/mm/YYYY, dd-mm-YYYY, dd.mm.YYYY (but not dd mm YYYY)
  • Supports dd mmm YYYY, dd-mmm-YYYY, dd/mmm/YYYY, dd.mmm.YYYY (dd mmm YYYY newly added. mmm can be in CAPITAL e.g. DEC or Title format e.g. Dec)

Some additional minor touch-up as follows:

  1. Included the fix by Ofir Luzon on February 14th 2019 to remove a comma that was in the regex which allowed dates like 29-0,-11 [error replicated to Alok Chaudhary's regex]

  2. Replaced (\/|-|\.) by ([-.\/]) to minimize the use of backslash. \/ is still used in order to support some regex flavor e.g. PCRE(PHP) although some other regex flavor e.g. Python can simply use / inside the character class [ ]

  3. Added a pair of parenthesis () surrounding the whole regex to make it a capturing group for the whole matching string. This is useful for people using findAll type of functions to get a matching item list (e.g. re.findall in Python). This enable us to capture all the matching strings within a mult-line string with the following codes:

re.findall sample codes:

match_list = re.findall(regex, source_string)
for item in match_list:
    print(item[0])

Extended regex image: enter image description here

Credits should go to Ofir Luzon and Alok Chaudhary who created such excellent regexes for us all!


I'm working with an API that only accepts MM/DD/YYYY format. I couldn't find any other post that did leap years quite as well as Ofir's answer, so I tweaked it and am re-posting it here for anyone that might need it.

/^(?:(?:(?:0[13578]|1[02])(\/)31)\1|(?:(?:0[1,3-9]|1[0-2])(\/)(?:29|30)\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:02(\/)29\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:(?:0?[1-9])|(?:1[0-2]))(\/)(?:0[1-9]|1\d|2[0-8])\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$/

I have extended the regex given by @Ofir Luzon for the formats dd-mmm-YYYY, dd/mmm/YYYY, dd.mmm.YYYY as per my requirement. Anyone else with same requirement can refer this

^(?:(?:31(\/|-|\.)(?:0?[13578]|1[02]|(?:Jan|Mar|May|Jul|Aug|Oct|Dec)))\1|(?:(?:29|30)(\/|-|\.)(?:0?[1,3-9]|1[0-2]|(?:Jan|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec))\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:29(\/|-|\.)(?:0?2|(?:Feb))\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\d|2[0-8])(\/|-|\.)(?:(?:0?[1-9]|(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep))|(?:1[0-2]|(?:Oct|Nov|Dec)))\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$

and tested for some test cases here http://regexr.com/39tr1.

For better understanding for this Regular expression refer this image: enter image description here


Another answer which validates day (dd) depending upon the month (mm) and the year (yyyy) (i.e., also validates 29th Feb in leap years) and allows years ranging from 0001 to 9999 (0000 in a invalid year according to the Gregorian calendar)

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

((((0[13578]|1[02])\/(0[1-9]|1[0-9]|2[0-9]|3[01]))|((0[469]|11)\/(0[1-9]|1[0-9]|2[0-9]|3[0]))|((02)(\/(0[1-9]|1[0-9]|2[0-8]))))\/(19([6-9][0-9])|20([0-9][0-9])))|((02)\/(29)\/(19(6[048]|7[26]|8[048]|9[26])|20(0[048]|1[26]|2[048])))

will validate MM/DD/YYYY format with 1960 to 2028

if you need to extend leap year support then add

19(6[048]|7[26]|8[048]|9[26])|20(0[048]|1[26]|2[048]|3[26]|4[048])))

this is also work

^((((0[13578]|1[02])[/](0[1-9]|1[0-9]|2[0-9]|3[01]))|((0[469]|11)[/](0[1-9]|1[0-9]|2[0-9]|3[0]))|((02)([/](0[1-9]|1[0-9]|2[0-8]))))[/](19([6-9][0-9])|20([0-9][0-9])))|((02)[/](29)[/](19(6[048]|7[26]|8[048]|9[26])|20(0[048]|1[26]|2[048])))

if you can change format mm-dd-yyyy than replace [/] to [-] also check online http://regexr.com/


^(((([13578]|0[13578]|1[02])[-](0[1-9]|[1-9]|1[0-9]|2[0-9]|3[01]))|(([469]|0[469]|11)[-]([1-9]|1[0-9]|2[0-9]|3[0]))|((2|02)([-](0[1-9]|1[0-9]|2[0-8]))))[-](19([6-9][0-9])|20([0-9][0-9])))|((02)[-](29)[-](19(6[048]|7[26]|8[048]|9[26])|20(0[048]|1[26]|2[048])))

this regex will validate dates in format:

12-30-2016 (mm-dd-yyyy) or 12-3-2016 (mm-d-yyyy) or 1-3-2016 (m-d-yyyy) or 1-30-2016 (m-dd-yyyy)


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

will validate any date between 1900-2099


I know it is a tangential answer to the question, but if the intention of the question is 'how do I validate a date?', then why not try letting the programming language do all the hard work (if you are using a language that can)?

e.g. in php

$this_date_object = date_create($this_date);

if ($this_date_object == false )
    {

        // process the error

    }