32

Is there any way to have a regex in JavaScript that validates dates of multiple formats, like: DD-MM-YYYY or DD.MM.YYYY or DD/MM/YYYY etc? I need all these in one regex and I'm not really good with it. So far I've come up with this: var dateReg = /^\d{2}-\d{2}-\d{4}$/; for DD-MM-YYYY. I only need to validate the date format, not the date itself.

Eduard Luca
  • 6,514
  • 16
  • 85
  • 137
  • 1
    You might be interested in http://www.datejs.com/ – Py. Sep 12 '11 at 12:42
  • If the only thing that varies is the separator then replace the `-` with `[\-\/\.]` (or whatever the escaping would be). – Dave Newton Sep 12 '11 at 12:42
  • It's your own custom format date string. International formats is: dd.mm.yyyy or mm/dd/yyyy or yyyy-mm-dd. – Andrew D. Sep 12 '11 at 13:27
  • This is the BEST answer, no ugly Regex and such: http://stackoverflow.com/questions/5774931/javascript-regular-expression-to-validate-date/5775146#5775146 – vsync Nov 14 '11 at 13:14
  • Please consider reassigning the correct answer. Current answer matches incorrect dates (99-99-9999, etc..). Thanks! – Dropout Dec 09 '15 at 07:40
  • @Dropout I've instead edited the question, to specify that I only needed to validate the format, not the actual date validity. If that were the case, @nicoabie's answer would have been better, even though it says `01.01-2015` is valid, so none of the answers correctly fully validate a date. Thanks for pointing this out, though. – Eduard Luca Dec 09 '15 at 11:01
  • 1
    @EduardLuca OK great, thank you too! just trying to make things more helpful for others which come to the question later ;) cheers! – Dropout Dec 09 '15 at 12:14

11 Answers11

44

You could use a character class ([./-]) so that the seperators can be any of the defined characters

var dateReg = /^\d{2}[./-]\d{2}[./-]\d{4}$/

Or better still, match the character class for the first seperator, then capture that as a group ([./-]) and use a reference to the captured group \1 to match the second seperator, which will ensure that both seperators are the same:

var dateReg = /^\d{2}([./-])\d{2}\1\d{4}$/

"22-03-1981".match(dateReg) // matches
"22.03-1981".match(dateReg) // does not match
"22.03.1981".match(dateReg) // matches
Billy Moon
  • 57,113
  • 24
  • 136
  • 237
21

Format, days, months and year:

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

David Hoerster
  • 28,421
  • 8
  • 67
  • 102
nicoabie
  • 2,684
  • 1
  • 20
  • 19
  • This partially validates the date, but still allows for dates like `30-02-2013` which is invalid. More complex rules are needed to account for different month lengths. – Billy Moon Mar 18 '13 at 11:44
  • 3
    Technically speaking @BillyMoon, we are actually validating its format, not the date itself. Yours allows dates like 30-02-2013 too my friend. – nicoabie Mar 18 '13 at 20:03
  • Yes, mine is designed to extract the numbers from valid dates, and does not attempt to do validation, which yours does. I think with some adjustment, you could have reasonable validation of dates, which I would like to see you do, but half validating them seems to me like having a weak fence on a cliff edge, better to have none at all, lest someone leans on it! Better still to have a strong one. – Billy Moon Mar 18 '13 at 20:25
  • @BillyMoon `Format, days, months and year:`, what are you talking about? – Dropout Dec 09 '15 at 08:33
  • @Dropout - is your question aimed at @nicoabie? – Billy Moon Dec 09 '15 at 18:13
  • @BillyMoon oh, sorry I thought you were talking about MM-DD-YYYY being an invalid format, now I noticed it's 30th Feb. My bad, sorry. – Dropout Dec 10 '15 at 06:28
13

The suggested regex will not validate the date, only the pattern.

So 99.99.9999 will pass the regex.

You later specified that you only need to validate the pattern but I still think it is more useful to create a date object

const isDDMMYYYY = str => {
  let [dd, mm, yyyy] = str.split(/[\.\-\/]/); // change to suit your locale
  dd = +dd;     // cast to number
  yyyy = +yyyy; // cast to number
  let mm0 = mm - 1, // js months are 0 based
    date = new Date(yyyy, mm0, dd, 15, 0, 0, 0); // normalise
  return mm0 === date.getMonth() && dd === date.getDate() && yyyy === date.getFullYear();
};
const dates = [
  "13-01-2023",
  "13.01.2023",
  "13/01/2023",
  "08-08-1991",
  "29/02/2011"
];

dates.forEach(date => console.log(date, ':', isDDMMYYYY(date)));
mplungjan
  • 169,008
  • 28
  • 173
  • 236
  • the validation of invalid date values will be done by me manually. if i enter something like 08-08-1991 with your solution, would get me an "Invalid Date" in javascript for some reason. – Eduard Luca Sep 12 '11 at 12:59
  • 1
    Not in Fx : I added that date to http://jsfiddle.net/mplungjan/Mqh8D/ What browser are you one? – mplungjan Sep 12 '11 at 19:43
  • If you use parseInt you MUST use the radix 10 since 08 and 09 are invalid octal numbers – mplungjan Sep 28 '12 at 16:07
  • Why do you increment and decrement the months ? See: `var date = new Date(yyyy,mm-1,dd,0,0,0,0);` (`(date.getMonth()+1)`) – Ndrslmpk May 17 '22 at 11:13
  • Js months are 0 based - I can decrement the month in the constructor or increment in the comparison – mplungjan May 17 '22 at 11:17
10

You can use regular multiple expressions with the use of OR (|) operator.

function validateDate(date){
    var regex=new RegExp("([0-9]{4}[-](0[1-9]|1[0-2])[-]([0-2]{1}[0-9]{1}|3[0-1]{1})|([0-2]{1}[0-9]{1}|3[0-1]{1})[-](0[1-9]|1[0-2])[-][0-9]{4})");
    var dateOk=regex.test(date);
    if(dateOk){
        alert("Ok");
    }else{
        alert("not Ok");
    }
}

Above function can validate YYYY-MM-DD, DD-MM-YYYY date formats. You can simply extend the regular expression to validate any date format. Assume you want to validate YYYY/MM/DD, just replace "[-]" with "[-|/]". This expression can validate dates to 31, months to 12. But leap years and months ends with 30 days are not validated.

djikay
  • 10,450
  • 8
  • 41
  • 52
5

Make use of brackets /^\d{2}[.-/]\d{2}[.-/]\d{4}$/ http://download.oracle.com/javase/tutorial/essential/regex/char_classes.html

Simon
  • 860
  • 7
  • 23
1

Please find in the below code which enables to perform the date validation for any of the supplied format or based on user locale to validate start/from and end/to dates. There could be some better approaches but have come up with this. Have tested it for the formats like: MM/dd/yyyy, dd/MM/yyyy, yyyy-MM-dd, yyyy.MM.dd, yyyy/MM/dd and dd-MM-yyyy.

Note supplied date format and date string go hand in hand.

    <script type="text/javascript">
function validate(format) {

    if(isAfterCurrentDate(document.getElementById('start').value, format)) {
        alert('Date is after the current date.');
    } else {
        alert('Date is not after the current date.');
    }
    if(isBeforeCurrentDate(document.getElementById('start').value, format)) {
        alert('Date is before current date.');
    } else {
        alert('Date is not before current date.');
    }
    if(isCurrentDate(document.getElementById('start').value, format)) {
        alert('Date is current date.');
    } else {
        alert('Date is not a current date.');
    }
    if (isBefore(document.getElementById('start').value, document.getElementById('end').value, format)) {
        alert('Start/Effective Date cannot be greater than End/Expiration Date');
    } else {
        alert('Valid dates...');
    }
    if (isAfter(document.getElementById('start').value, document.getElementById('end').value, format)) {
        alert('End/Expiration Date cannot be less than Start/Effective Date');
    } else {
        alert('Valid dates...');
    }
    if (isEquals(document.getElementById('start').value, document.getElementById('end').value, format)) {
        alert('Dates are equals...');
    } else {
        alert('Dates are not equals...');
    }
    if (isDate(document.getElementById('start').value, format)) {
        alert('Is valid date...');
    } else {
        alert('Is invalid date...');
    }
}

/**
 * This method gets the year index from the supplied format
 */
function getYearIndex(format) {

    var tokens = splitDateFormat(format);

    if (tokens[0] === 'YYYY'
            || tokens[0] === 'yyyy') {
        return 0;
    } else if (tokens[1]=== 'YYYY'
            || tokens[1] === 'yyyy') {
        return 1;
    } else if (tokens[2] === 'YYYY'
            || tokens[2] === 'yyyy') {
        return 2;
    }
    // Returning the default value as -1
    return -1;
}

/**
 * This method returns the year string located at the supplied index
 */
function getYear(date, index) {

    var tokens = splitDateFormat(date);
    return tokens[index];
}

/**
 * This method gets the month index from the supplied format
 */
function getMonthIndex(format) {

    var tokens = splitDateFormat(format);

    if (tokens[0] === 'MM'
            || tokens[0] === 'mm') {
        return 0;
    } else if (tokens[1] === 'MM'
            || tokens[1] === 'mm') {
        return 1;
    } else if (tokens[2] === 'MM'
            || tokens[2] === 'mm') {
        return 2;
    }
    // Returning the default value as -1
    return -1;
}

/**
 * This method returns the month string located at the supplied index
 */
function getMonth(date, index) {

    var tokens = splitDateFormat(date);
    return tokens[index];
}

/**
 * This method gets the date index from the supplied format
 */
function getDateIndex(format) {

    var tokens = splitDateFormat(format);

    if (tokens[0] === 'DD'
            || tokens[0] === 'dd') {
        return 0;
    } else if (tokens[1] === 'DD'
            || tokens[1] === 'dd') {
        return 1;
    } else if (tokens[2] === 'DD'
            || tokens[2] === 'dd') {
        return 2;
    }
    // Returning the default value as -1
    return -1;
}

/**
 * This method returns the date string located at the supplied index
 */
function getDate(date, index) {

    var tokens = splitDateFormat(date);
    return tokens[index];
}

/**
 * This method returns true if date1 is before date2 else return false
 */
function isBefore(date1, date2, format) {
    // Validating if date1 date is greater than the date2 date
    if (new Date(getYear(date1, getYearIndex(format)), 
            getMonth(date1, getMonthIndex(format)) - 1, 
            getDate(date1, getDateIndex(format))).getTime()
        > new Date(getYear(date2, getYearIndex(format)), 
            getMonth(date2, getMonthIndex(format)) - 1, 
            getDate(date2, getDateIndex(format))).getTime()) {
        return true;
    } 
    return false;                
}

/**
 * This method returns true if date1 is after date2 else return false
 */
function isAfter(date1, date2, format) {
    // Validating if date2 date is less than the date1 date
    if (new Date(getYear(date2, getYearIndex(format)), 
            getMonth(date2, getMonthIndex(format)) - 1, 
            getDate(date2, getDateIndex(format))).getTime()
        < new Date(getYear(date1, getYearIndex(format)), 
            getMonth(date1, getMonthIndex(format)) - 1, 
            getDate(date1, getDateIndex(format))).getTime()
        ) {
        return true;
    } 
    return false;                
}

/**
 * This method returns true if date1 is equals to date2 else return false
 */
function isEquals(date1, date2, format) {
    // Validating if date1 date is equals to the date2 date
    if (new Date(getYear(date1, getYearIndex(format)), 
            getMonth(date1, getMonthIndex(format)) - 1, 
            getDate(date1, getDateIndex(format))).getTime()
        === new Date(getYear(date2, getYearIndex(format)), 
            getMonth(date2, getMonthIndex(format)) - 1, 
            getDate(date2, getDateIndex(format))).getTime()) {
        return true;
    } 
    return false;
}

/**
 * This method validates and returns true if the supplied date is 
 * equals to the current date.
 */
function isCurrentDate(date, format) {
    // Validating if the supplied date is the current date
    if (new Date(getYear(date, getYearIndex(format)), 
            getMonth(date, getMonthIndex(format)) - 1, 
            getDate(date, getDateIndex(format))).getTime()
        === new Date(new Date().getFullYear(), 
                new Date().getMonth(), 
                new Date().getDate()).getTime()) {
        return true;
    } 
    return false;                
}

/**
 * This method validates and returns true if the supplied date value 
 * is before the current date.
 */
function isBeforeCurrentDate(date, format) {
    // Validating if the supplied date is before the current date
    if (new Date(getYear(date, getYearIndex(format)), 
            getMonth(date, getMonthIndex(format)) - 1, 
            getDate(date, getDateIndex(format))).getTime()
        < new Date(new Date().getFullYear(), 
                new Date().getMonth(), 
                new Date().getDate()).getTime()) {
        return true;
    } 
    return false;                
}

/**
 * This method validates and returns true if the supplied date value 
 * is after the current date.
 */
function isAfterCurrentDate(date, format) {
    // Validating if the supplied date is before the current date
    if (new Date(getYear(date, getYearIndex(format)), 
            getMonth(date, getMonthIndex(format)) - 1, 
            getDate(date, getDateIndex(format))).getTime()
        > new Date(new Date().getFullYear(),
                new Date().getMonth(), 
                new Date().getDate()).getTime()) {
        return true;
    } 
    return false;                
}

/**
 * This method splits the supplied date OR format based 
 * on non alpha numeric characters in the supplied string.
 */
function splitDateFormat(dateFormat) {
    // Spliting the supplied string based on non characters
    return dateFormat.split(/\W/);
}

/*
 * This method validates if the supplied value is a valid date.
 */
function isDate(date, format) {                
    // Validating if the supplied date string is valid and not a NaN (Not a Number)
    if (!isNaN(new Date(getYear(date, getYearIndex(format)), 
            getMonth(date, getMonthIndex(format)) - 1, 
            getDate(date, getDateIndex(format))))) {                    
        return true;
    } 
    return false;                                      
}

Below is the HTML snippet

    <input type="text" name="start" id="start" size="10" value="05/31/2016" />
    <br/> 
    <input type="text" name="end" id="end" size="10" value="04/28/2016" />
    <br/>
    <input type="button" value="Submit" onclick="javascript:validate('MM/dd/yyyy');" />
Dinesh Lomte
  • 569
  • 7
  • 5
0

@mplungjan, @eduard-luca

function isDate(str) {    
    var parms = str.split(/[\.\-\/]/);
    var yyyy = parseInt(parms[2],10);
    var mm   = parseInt(parms[1],10);
    var dd   = parseInt(parms[0],10);
    var date = new Date(yyyy,mm-1,dd,12,0,0,0);
    return mm === (date.getMonth()+1) && 
        dd === date.getDate() && 
        yyyy === date.getFullYear();
}

new Date() uses local time, hour 00:00:00 will show the last day when we have "Summer Time" or "DST (Daylight Saving Time)" events.

Example:

new Date(2010,9,17)
Sat Oct 16 2010 23:00:00 GMT-0300 (BRT)

Another alternative is to use getUTCDate().

Francisco Kahil
  • 343
  • 2
  • 6
0

To make sure it will work, you need to validate it.

function mmIsDate(str) {

    if (str == undefined) { return false; }

    var parms = str.split(/[\.\-\/]/);

    var yyyy = parseInt(parms[2], 10);

    if (yyyy < 1900) { return false; }

    var mm = parseInt(parms[1], 10);
    if (mm < 1 || mm > 12) { return false; }

    var dd = parseInt(parms[0], 10);
    if (dd < 1 || dd > 31) { return false; }

    var dateCheck = new Date(yyyy, mm - 1, dd);
    return (dateCheck.getDate() === dd && (dateCheck.getMonth() === mm - 1) && dateCheck.getFullYear() === yyyy);

};
0

If you want to validate your date(YYYY-MM-DD) along with the comparison it will be use full for you...

    function validateDate()
    {
     var newDate = new Date();
     var presentDate = newDate.getDate();
     var presentMonth = newDate.getMonth();
     var presentYear = newDate.getFullYear();
     var dateOfBirthVal = document.forms[0].dateOfBirth.value;
    if (dateOfBirthVal == null) 
    return false;
    var validatePattern = /^(\d{4})(\/|-)(\d{1,2})(\/|-)(\d{1,2})$/;
    dateValues = dateOfBirthVal.match(validatePattern);
    if (dateValues == null) 
    {
        alert("Date of birth should be null and it should in the format of yyyy-mm-dd")
    return false;
        }
    var birthYear = dateValues[1];        
    birthMonth = dateValues[3];
    birthDate=  dateValues[5];
    if ((birthMonth < 1) || (birthMonth > 12)) 
    {
        alert("Invalid date")
    return false;
        }
    else if ((birthDate < 1) || (birthDate> 31)) 
    {
        alert("Invalid date")
    return false;
        }
    else if ((birthMonth==4 || birthMonth==6 || birthMonth==9 || birthMonth==11) && birthDate ==31) 
    {
        alert("Invalid date")
    return false;
        }
    else if (birthMonth == 2){ 
    var isleap = (birthYear % 4 == 0 && (birthYear % 100 != 0 || birthYear % 400 == 0));
    if (birthDate> 29 || (birthDate ==29 && !isleap)) 
    {
        alert("Invalid date")
    return false;
        }
    }
    else if((birthYear>presentYear)||(birthYear+70<presentYear))
        {
        alert("Invalid date")
        return false;
        }
    else if(birthYear==presentYear)
        {
        if(birthMonth>presentMonth+1)
            {
            alert("Invalid date")
            return false;
            }
        else if(birthMonth==presentMonth+1)
            {
            if(birthDate>presentDate)
                {
                alert("Invalid date")
                return false;
                }
            }
        }
return true;
    }
droidev
  • 7,352
  • 11
  • 62
  • 94
Ram Thota
  • 539
  • 5
  • 9
0

Try this:

^\d\d[./-]\d\d[./-]\d\d\d\d$
m.edmondson
  • 30,382
  • 27
  • 123
  • 206
0

Don't re-invent the wheel. Use a pre-built solution for parsing dates, like http://www.datejs.com/

Chris
  • 9,994
  • 3
  • 29
  • 31
  • 3
    the reason i don't want to add an external library is that it's not necessary, it would only make the site load slower. but yes, that would have been a solution – Eduard Luca Sep 12 '11 at 12:58