Click here to Skip to main content
Click here to Skip to main content

JavaScript Date Validation

By , 29 Nov 2012
 
For a few days now, I have been battling with the problem of JavaScript date validation. I wanted to validate text inputed by a user as they were typing to tell them if it was a valid date. After much searching on the internet, I found nothing that worked. So I wrote the following code to do the job, it is a simple but effective isDate function:
 
//Value parameter - required. All other parameters are optional.
function isDate(value, sepVal, dayIdx, monthIdx, yearIdx) {
    try {
        //Change the below values to determine which format of date you wish to check. It is set to dd/mm/yyyy by default.
        var DayIndex = dayIdx !== undefined ? dayIdx : 0; 
        var MonthIndex = monthIdx !== undefined ? monthIdx : 0;
        var YearIndex = yearIdx !== undefined ? yearIdx : 0;
 
        value = value.replace(/-/g, "/").replace(/\./g, "/"); 
        var SplitValue = value.split(sepVal || "/");
        var OK = true;
        if (!(SplitValue[DayIndex].length == 1 || SplitValue[DayIndex].length == 2)) {
            OK = false;
        }
        if (OK && !(SplitValue[MonthIndex].length == 1 || SplitValue[MonthIndex].length == 2)) {
            OK = false;
        }
        if (OK && SplitValue[YearIndex].length != 4) {
            OK = false;
        }
        if (OK) {
            var Day = parseInt(SplitValue[DayIndex], 10);
            var Month = parseInt(SplitValue[MonthIndex], 10);
            var Year = parseInt(SplitValue[YearIndex], 10);
 
            if (OK = ((Year > 1900) && (Year < new Date().getFullYear()))) {
                if (OK = (Month <= 12 && Month > 0)) {

                    var LeapYear = (((Year % 4) == 0) && ((Year % 100) != 0) || ((Year % 400) == 0));   
                    
                    if(OK = Day > 0)
                    {
                        if (Month == 2) {  
                            OK = LeapYear ? Day <= 29 : Day <= 28;
                        } 
                        else {
                            if ((Month == 4) || (Month == 6) || (Month == 9) || (Month == 11)) {
                                OK = Day <= 30;
                            }
                            else {
                                OK = Day <= 31;
                            }
                        }
                    }
                }
            }
        }
        return OK;
    }
    catch (e) {
        return false;
    }
} 
 
Just copy the above function and call isDate(value) where value is a string containing a valid or invalid date. The function returns a bool true if the string was a date and false if it wasn't. Hope this helps! Smile | <img src= " />
 
EDIT: Thanks to Member 2792937 for bringing a bug to my attention.
 
Both parseInt('08') and parseInt('09') return zero because the function tries to determine the correct base for the numerical system used. In JavaScript, numbers starting with zero are considered octal and there's no 08 or 09 in octal, hence the problem.
 
To fix this, just add the second parameter for parseInt, the base to be used for the conversion. The correct calls should be parseInt('08', 10) and parseInt('09', 10).

(From http://www.ventanazul.com/webzine/articles/issues-parseint-javascript[^])
 
I have modified my code to fix this issue.

EDIT: Now includes optional parameters for specifying separator value and the indexes. To miss out a parameter simply pass in undefined. Thanks to Lester Callif for the suggestions.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Ed Nutting
Founder Slide My Way Limited
United Kingdom United Kingdom
Member
Hi there, so you're reading this? I probably ought to tell you something helpful then...
 
Okay well, I'm 17 from London, UK and I have been programming since I was 8 years old. You'll see from my profile I've dabbled in a lot of different areas and I do know what I'm talking about so as they say "gimme some respect yeah?" Smile | :) I've done GCSE's (got 7A*'s, 2A's and a B in French) and am now studying for my AS-Levels (Math, Further Maths, Physics and Chemistry). My main aim is to go to university to study electronic engineering and then work in robotics (preferably humanoid but most of the field is interesting).
 

I have recently launched my website www.slidemyway.co.uk so please head over and take a look! All support and feedback is welcome!

 
Thanks for reading,
Edward Nutting

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
SuggestionNewer version [modified]memberMaster DJon5 Dec '12 - 6:24 
Here is a another version which I removed the year validation that shall be between some years. I think that this check shall be done outside the function as its purpose shall be any date validation only. My opinion here. Though, the part I consider a real amelioration is the auto detection of indexes. This functionnality supports YYYY-mm-dd & dd-mm-YYYY. So, the usage of any other format shall then pass the parameters of indexes. The minimal year supported by this autodetection is 32. Though, another validation makes it impossible to go lower than year 1000.
 
//Value parameter - required. All other parameters are optional.
function isDate(value, sepVal, dayIdx, monthIdx, yearIdx) {
    try {
        value = value.replace(/-/g, "/").replace(/\./g, "/");
	sepVal = (sepVal === undefined ? "/" : sepVal.replace(/-/g, "/").replace(/\./g, "/"));
 
        var SplitValue = value.split(sepVal);
        if (SplitValue.length != 3) {
            return false;
        }
 
        //Auto  detection of indexes
        if (dayIdx === undefined || monthIdx === undefined || yearIdx === undefined) {
            if (SplitValue[0] > 31) {
                yearIdx = 0;
                monthIdx = 1;
                dayIdx = 2;
            } else {
                yearIdx = 2;
                monthIdx = 1;
                dayIdx = 0;
            }
        }
 
        //Change the below values to determine which format of date you wish to check. It is set to dd/mm/yyyy by default.
        var DayIndex = dayIdx !== undefined ? dayIdx : 0;
        var MonthIndex = monthIdx !== undefined ? monthIdx : 1;
        var YearIndex = yearIdx !== undefined ? yearIdx : 2;
 
        var OK = true;
        if (!(SplitValue[DayIndex].length == 1 || SplitValue[DayIndex].length == 2)) {
            OK = false;
        }
        if (OK && !(SplitValue[MonthIndex].length == 1 || SplitValue[MonthIndex].length == 2)) {
            OK = false;
        }
        if (OK && SplitValue[YearIndex].length != 4) {
            OK = false;
        }
        if (OK) {
            var Day = parseInt(SplitValue[DayIndex], 10);
            var Month = parseInt(SplitValue[MonthIndex], 10);
            var Year = parseInt(SplitValue[YearIndex], 10);
            var MonthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
 
            if (OK = (Month <= 12 && Month > 0)) {
 
                var LeapYear = (Year & 3) == 0 && ((Year % 25) != 0 || (Year & 15) == 0);
                MonthDays[1] = (LeapYear ? 29 : 28);
 
                OK = Day > 0 && Day <= MonthDays[Month - 1];
            }
        }
        return OK;
    }
    catch (e) {
        return false;
    }
}


modified 5 Mar '13 - 14:54.

GeneralRe: Newer versionmemberjoni8a5 Mar '13 - 3:30 
Hello,
 
I am tring to use your code like this:
date = "30.12.1990";
  alert(isDate(date,"."));
 
But the functions returns false, why is that so??
 
joni8a
AnswerRe: Newer versionmemberMaster DJon5 Mar '13 - 7:10 
You were right. I did some modifications, but did not try all the possibilities... So hyphens and dots were not valid separators... Now they are !
AnswerRe: Newer versionmemberMaster DJon5 Mar '13 - 8:55 
I modified the code a little bit to optimize it. Though, even with a one million loop, it doesn't make much difference.
QuestionShorter codememberredphx4 Dec '12 - 20:13 
How about this?
 
var isDateValid=function(b,c,d){var a=new Date(b,c-1,d);return a.getDate()==d&&a.getMonth()==c-1&&a.getFullYear()==b};
 
b = year
c = month
d = day
QuestionAlternative to parseInt()memberXunrel4 Dec '12 - 6:03 
Another way to parse a string which has a leading '0' you can use the following code:
 
var test = '08';
var numberTest = (+test);
console.log(numberTest); // will log 8 as number
 
And thanks for the code, I also tried something like this Wink | ;)
QuestionImpressive, but have a couple of mods that should take care of both the date format and the separator for diff countries.memberLester Callif27 Nov '12 - 15:46 
function isDate(value, sepVal, monIdx, dayIdx, yearIdx) {
    try {
        //Change the below values to determine which format of date you wish to check. It is set to dd/mm/yyyy by default.
        var DayIndex = dayIdx;
        var MonthIndex = monIdx;
        var YearIndex = yearIdx;
 
        value = value.replace(/-/g, "/").replace(/\./g, "/");
        var SplitValue = value.split(sepVal);
 
Where the the following would hold true for the original posting:
sepVal = "/"
dayIdx = 0
monIdx = 1
yearIdx = 2
 
If you wanted to validate a date in a format of "YYYY-mm-dd" the following would be the values to be passed in:
sepVal = "-"
 dayIdx = 2
 monIdx = 1
 yearIdx = 0
 
Thanks for the FANTASTIC start Ed!!!!
AnswerRe: Impressive, but have a couple of mods that should take care of both the date format and the separator for diff countries.memberEd Nutting29 Nov '12 - 10:52 
Hi,
 
I like the idea of the sepVal specifier - I might add that in when I get some spare time. Not so sure about the extra parameters - too much risk for inconsistency within an application I fear. However, I could make them optional parameters which would work quite nicely - I will look into doing that too, at some point Smile | :)
 
Thanks for your feedback - glad you found the code useful!
Ed
GeneralRe: Impressive, but have a couple of mods that should take care of both the date format and the separator for diff countries.memberLester Callif29 Nov '12 - 12:50 
I am ALWAYS learning. As such, would it be possible to expand on the inconsistency issue you see, please ? Thanks!!!
AnswerRe: Impressive, but have a couple of mods that should take care of both the date format and the separator for diff countries.memberEd Nutting30 Nov '12 - 9:16 
Yeah sure I can Smile | :)
 
So when developing a small web application it is very easy to copy/paste code from one place to another and just make sure later that you change all the copies if you ever want to change something. This is made much easier by the fact that there is probably only a development team of < 5 people. However, inconsistency issues can arise if this technique is used when scaling up. For instance, if you take on a new member of staff, say someone from Europe for example. Now all of your code may be programmed using the traditionally British style of dd/mm/yyyy but your new European employee may use mm.dd.yyyy. If you set that new employee on a programming task and they forget (as they likely will) that the British standard should be used, you have immediately built in an inconsistency into your web application (which clearly is bad from a UI point of view and for data checking/verification). Furthermore, if the code is then copied around the place, a larger development team will rapidly lose track of where all the copies of the date checking code calls are and thus if you change to a different date format you can't guarantee you have changed all your code! Sigh | :sigh: A final problem is that say you wanted to run two versions of your site, one for Europe one for UK. Naturally you want to make as few changes as possible or even run the site as one website with automatic detection of where a request is coming from. If you have copied calls to isDate all over the place specifying different date formats for each call you will have yourself an all mighty mess trying to convert it for the new site.
 
So why is having one call with few parameters, and have defaults built in to the isDate function, better?
- If you change format, you change the code in one place and have site-wide results in seconds.
- If you want to build in request location detection, you can do it simply in the isDate function - one change, one place, very easy.
- If a developer new to the code needs to change something in the date validation, they only need to change it in one place and do not need to check every call to isDate to check that nothing is broken/unexpected or worse still, needs redoing.
 
So clearly in bigger applications it becomes more sensible to copy as little as possible and have it all in one place. If you did want to separate out the date format from the date validation, it should be done by creating a new method/JS file to contain one set of code for doing the format checking and that new code should be called from one place (in the isDate cycle) - from within isDate, not by methods calling isDate else you'd be back to the problem of duplicated code Smile | :)
 
Hope explains things well enough,
Ed
AnswerRe: Impressive, but have a couple of mods that should take care of both the date format and the separator for diff countries.memberEd Nutting29 Nov '12 - 11:01 
When I said "When I get some spare time", I probably should have said "In 5 minutes" Poke tongue | ;-P
 
Ed
QuestionJust one bug in FebruarymemberMember 324090521 Nov '12 - 12:37 
You forgot to check if the Day is greater than zero.
Should be something like this:
OK = Day > 0 && (LeapYear ? Day <= 29 : Day <= 28);
 
Apart from that, very good code.
AnswerRe: Just one bug in FebruarymemberEd Nutting25 Nov '12 - 11:09 
I'm surprised neither I nor anybody else spotted this sooner! I have updated the code to fix this.
 
Thanks and glad the code helped,
Ed
QuestionDesign flaw in your codememberMember 942879613 Sep '12 - 13:38 
The line reading:
if (OK = ((Year > 1900) && (Year < new Date().getFullYear()))) {
is not a good idea. First off, it causes dates from the current year to be judged to be invalid. I think you meant <= rather than <.
 
Second, this line makes the assumption that a year less than 1900 is invalid. There's no reason for a general-purpose function such as this one to assume something like that. 1899 is a perfectly valid date.
 
A better design for this line, and the one I'm now using, is:
if (OK = ((Year >= 1000) && (Year <= 9999))) {
This way it simply insures that the year is a four-digit number, which is, I think, what this function should do.
AnswerRe: Design flaw in your codememberEd Nutting13 Sep '12 - 20:26 
Well to start with if you read the messages below titled "Year Validation" you would see that this "issue" has already been covered. I did not mean <=, I meant <. No matter what I put in the code it will never satisfy everyone, as this is one of the things where everyone has different needs depending upon application. The code is readable/good enough that you found how to change this piece of validation so it isn't much of a problem.
 
Secondly, I should probably have assumed the date shouldn't be less than 1970, given that a number of computer date systems don't handle dates less than 1970 so a "general-purpose function" would account for that. For example the minimum positive date for Java code is Jan 1 1970 (my code only allows positive dates) so if you were using a Java server, your code would not work.
 
Finally, to re-iterate what I said before, better design for you but not for me, or the other poster below or anyone else who needed something different to what you do. For example, in my application I wanted real birth dates and I was targeting younger people of similar age to myself, so a birth date of < 1900 was unrealistic.
 
Hope this answers your query,
Ed
BugYear ValidationmemberXtremLucky24 Apr '12 - 3:05 
The Script you wrote has a small bug.
This check if (OK = ((Year > 1900) && (Year < new Date().getFullYear())))
only checks <(less than) or >(greater than) value and hence returns false even when
it should not (eg 2012 < 2012 ).
 
Please take a note of it.
Rest all is fine.
Good Work.! Smile | :)
- Regards Xtrem - Wink | ;) Ω

GeneralRe: Year ValidationmemberEd Nutting24 Apr '12 - 6:16 
Thank you for pointing this out to other users but what you call a bug, I call intended design Wink | ;) Unusual, I know and probably worth other users noting, sorry if this caused you an issue. I tried to make the code readable enough so that things like this could be changed easily though. You could argue that blocking dates above the current year is a bug, could you not? I think you see where that though leads...
 
Best regards,
Ed
GeneralRe: Year Validationmembergreg_ryan17 Jul '12 - 12:54 
That'd be true if the date entered within the current year was actually larger than today's date Smile | :) Otherwise, nice script and thank you!
Greg

GeneralMinor Bug Fix for the non-slash people...memberEd Nutting13 Mar '12 - 12:11 
Very minor improvement (bug fix) with the replacing of dots or dashes as separators - replace in Javascript only replaces first occurrence of a string rather unless regex with global replace is used - this is now done so that it actually works as intended - i.e. it converts the following dates to the following result before processing:
Input : Processed Input
1/1/1 : 1/1/1
1.1.1 : 1/1/1
1-1-1 : 1/1/1
 
Surprised nobody noticed this before... Anyway best regards,
Ed
GeneralI am *very* surprised that none of our North American friend...memberPeter_in_278026 Sep '11 - 16:15 
I am *very* surprised that none of our North American friends (who think a date goes mm/dd/yyyy) or Europeans who use separators other than '/' has complained that their format doesn't work.
GeneralRe: Yes I guess that is a little surprising. But then again, I w...memberEdward Nutting26 Sep '11 - 20:19 
Yes I guess that is a little surprising. But then again, I would hope it is fairly simple to adapt my code. Although I would like to point out that my code does allow for the separators '/', '.' and '-' so that should cover a lot of them. Furthermore, to simply switch the values around isn't hard...just change the indexes in the value array to what you want. Smile | :) I think I'll update have updated my code to make that easier - it's only a simple change!
GeneralReason for my vote of 5 found to be complete, simple and ele...memberrquadros25 Jul '11 - 12:34 
Reason for my vote of 5
found to be complete, simple and elegant code.
QuestionBug with year validationmemberMember 842090121 Nov '11 - 5:59 
I believe that the snippet
(Year < new Date().getFullYear())
should actually be
(Year <= new Date().getFullYear())
to allow this year to be chosen.
AnswerRe: Bug with year validationmemberEdward Nutting21 Nov '11 - 9:42 
Thanks for that - at the moment there appears to be a bug when trying to modify/improve my tip/trick so I can't change the code. Really that line just depends on what you want to be the max year. I will add this variable in when I get the chance. For what I wanted, I didn't want to allow the current year.
 
Hope this explains,
Ed Smile | :)
QuestionparseInt() issue when value is '08' or '09'memberMember 279293720 Sep '11 - 19:34 
See http://www.ventanazul.com/webzine/articles/issues-parseint-javascript[^]
 
Just need to add the base (10) to the parseInt() call.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 29 Nov 2012
Article Copyright 2011 by Ed Nutting
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid