2081

I'd like to tell the difference between valid and invalid date objects in JS, but couldn't figure out how:

var d = new Date("foo");
console.log(d.toString()); // shows 'Invalid Date'
console.log(typeof d); // shows 'object'
console.log(d instanceof Date); // shows 'true'

Any ideas for writing an isValidDate function?

  • Ash recommended Date.parse for parsing date strings, which gives an authoritative way to check if the date string is valid.
  • What I would prefer, if possible, is have my API accept a Date instance and to be able to check/assert whether it's valid or not. Borgar's solution does that, but I need to test it across browsers. I also wonder whether there's a more elegant way.
  • Ash made me consider not having my API accept Date instances at all, this would be easiest to validate.
  • Borgar suggested testing for a Date instance, and then testing for the Date's time value. If the date is invalid, the time value is NaN. I checked with ECMA-262 and this behavior is in the standard, which is exactly what I'm looking for.
Servy
  • 202,030
  • 26
  • 332
  • 449
orip
  • 73,323
  • 21
  • 116
  • 148
  • 1
    I deleted my original answer since checking if NaN is a much better solution than comparing to a string "Invalid Date". I'll have to make use of the isNaN solution, myself. – Chris Charabaruk Aug 30 '09 at 11:55
  • @orip, "have my API accept a Date instance and to be able to check/assert whether it's valid or not" Have you tried: isNan(d.getTime())==true on the date instance? – Ash Aug 30 '09 at 17:49
  • @Ash, yes - that's what Borgar suggested. I looked up the ECMA-262 definition of Date's methods, and getTime isn't guaranteed to return NaN. The other "get*" methods, such as getMonth, are. – orip Aug 30 '09 at 20:21
  • Oops, my bad - getTime returns NaN just fine (returns "the time value", which is NaN if the date is invalid) – orip Aug 30 '09 at 20:25
  • 20
    You could remove the if statement by changing the body of the function to: `return ( Object.prototype.toString.call(d) === "[object Date]" && !isNaN(d.getTime()) );` – styfle Jun 23 '11 at 23:35
  • 3
    @styfle - sure, but why? – orip Jun 25 '11 at 14:39
  • @orip It makes the code more readable. The more ifs, returns, nots, etc can make the code more confusing. The same reason you don't do `if (!bool == false) return false;` – styfle Jun 25 '11 at 21:15
  • 3
    @styfle - guess it's a style preference: I find it clearer to separate the type check from the equality logic. – orip Jun 27 '11 at 13:05
  • Please keep in mind that `Date.parse` is dependent on the implementation, see http://stackoverflow.com/questions/3085937/safari-js-cannot-parse-yyyy-mm-dd-date-format – Christoph Baudson Nov 29 '11 at 12:28
  • Why var d = new Date("30/30/44"); isValidDate(d); returning true? – kiranvj Sep 21 '12 at 17:44
  • It didn't work in IE8 - Please see here http://stackoverflow.com/questions/13878515/javascript-valid-date-checking-does-not-work-in-ie8 – LCJ Dec 14 '12 at 12:16
  • IE rolls over it's months. A month of 30 is actually seen as 2 years and 6 months. So 30/30/44 in IE creates a date object of June 30, 46. The Date object is valid so it passes the above test. (It probably rolls over it's days as well) – Corey Ogburn Feb 21 '14 at 18:54
  • So `Object.prototype.toString.call(obj) === "[object Date]" && !isNaN(obj)` wins. Cool. However, the test for a Date instance should be separate from the test of whether it contains a valid time value as they are separate concerns. – RobG Oct 16 '15 at 04:35
  • Why isn't this adequate: `return d.toString() !== 'Invalid Date'` ? I assume that value is defined in the spec and thus as reliable as e.g. values produced by `typeof`. – Tom Mar 14 '21 at 02:41
  • Why not Tom's answer or `date == 'Invalid Date'`? – Cody May 25 '22 at 15:22

54 Answers54

1802

Here's how I would do it:

if (Object.prototype.toString.call(d) === "[object Date]") {
  // it is a date
  if (isNaN(d)) { // d.getTime() or d.valueOf() will also work
    // date object is not valid
  } else {
    // date object is valid
  }
} else {
  // not a date object
}

Update [2018-05-31]: If you are not concerned with Date objects from other JS contexts (external windows, frames, or iframes), this simpler form may be preferred:

function isValidDate(d) {
  return d instanceof Date && !isNaN(d);
}

Update [2021-02-01]: Please note that there is a fundamental difference between "invalid dates" (2013-13-32) and "invalid date objects" (new Date('foo')). This answer does not deal with validating date input, only if a Date instance is valid.

Borgar
  • 37,817
  • 5
  • 41
  • 42
  • 26
    instanceof breaks across frames. Duck-typing can work just fine too: validDate == d && d.getTime && !isNaN(d.getTime()); -- Since the question is for a general utility function I prefer to be more strict. – Borgar Aug 30 '09 at 12:14
  • 1
    @Borgar, I don't understand why instanceof breaks across frames. What sort of "frame" are you refer to? Also, how stable is the string "[object Date]"? – Ash Aug 31 '09 at 05:31
  • 13
    @Borgar, just found my answer: "The problems arise when it comes to scripting in multi-frame DOM environments. In a nutshell, Array objects created within one iframe do not share [[Prototype]]’s with arrays created within another iframe. Their constructors are different objects and so both instanceof and constructor checks fail." – Ash Aug 31 '09 at 05:35
  • 82
    you don't even need `d.getTime` just `isNan(d)` – TecHunter May 30 '13 at 08:26
  • 3
    Yes it does, @Jerry, "valid date objects" and "valid dates" are not the same thing: stackoverflow.com/a/13897331/27388 – Borgar Jun 08 '15 at 11:34
  • 22
    Could be simplified like this: `d instanceof Date && !isNaN(d.getTime())` – Zorgatone Apr 07 '17 at 15:27
  • 3
    Does not work at ALL. This will accept any date object using any day/month/year combination, even if its invalid. – blueprintchris May 11 '18 at 10:09
  • 1
    A one-liner for this functions is: `Object.prototype.toString.call(d) === '[object Date]' && !Number.isNaN(d.getTime()`. Will return true if is a valid date, false if not. – Obed Parlapiano May 29 '18 at 12:12
  • 1
    Shouldn't the updated function be `return d instanceof Date && !isNaN(d.getTime());`? – Bart de Ruijter Jun 21 '18 at 08:22
  • 10
    Thanks for the answer, but I wish to stress @Borgar and @blueprintChris comments: if I parse the digit `1` for example I would still have a valid date resulting to `Mon Jan 01 2001 00:00:00` which is indeed a date, however for the purpose of my application it is completely useless. Thus, there is some more input validation needed in my case at least. This answer validates a `dateObject` not a `Date`! – dnhyde Sep 22 '18 at 10:20
  • I ended up writing my own date parser taking inspiration from this answer already posted by @Borgar in the comments (stackoverflow.com/a/13897331/27388) there they suggest using [date js library](http://www.datejs.com/). I'm developing in Vue so [vee-validate](https://baianat.github.io/vee-validate/) is a nice alternative if you use Vue as well, however the last version clashes with v-model directive, that's why I went back to plain js. – dnhyde Sep 22 '18 at 16:57
  • I think you're missing a `+` in your final formula: `function isValidDate(d) { return d instanceof Date && !isNaN(+d); }` – Sampgun Oct 26 '18 at 08:56
  • 1
    Your second function is not correct syntax: `Argument of type 'Date' is not assignable to parameter of type 'number'`. How can you test an instance of Date to be not a number while isNaN() expects a number but you already know it is a Date object? – Mick Feb 21 '19 at 12:19
  • 1
    Hi. In this case, the string is clearly not a date, but this function returns a true: `isValidDate(new Date('something that is a string with a version that seems a date like: 7.8.10'))` returns `true` – Daniele Vrut Apr 08 '19 at 15:13
  • 2
    Trying the second example, it did no work for me. I needed to change the second part to: `!isNaN(d.getTime());` – Andre M Jun 12 '19 at 00:48
  • 1
    @Sampgun `isNaN` converts it into a numeral value. It is `Number.isNaN` that you need the `+` numericalization operator for. – Константин Ван Aug 26 '19 at 22:12
  • @КонстантинВан you're right. `isNaN' does the conversion already. – Sampgun Aug 28 '19 at 09:50
  • Your first example with the `Object.prototype.toString.call` is how backbonejs handles their `is______()` calls, so +1 to that version. https://underscorejs.org/#isDate and github https://github.com/jashkenas/underscore/blob/master/underscore.js – NuclearPeon Sep 17 '19 at 00:09
  • 1
    It doesn't work if date is provided as "yyyy-mm-dd" – Istorn Nov 06 '19 at 13:40
  • 4
    This will trigger a TypeScript error, `TS2345: Argument of type 'Date' is not assignable to parameter of type 'number'`. – Dan Dascalescu May 27 '20 at 07:37
  • 2
    @DanDascalescu thats how I did it `isNaN(date.getTime())` – richardsonwtr Sep 04 '20 at 15:26
  • this doesn't seem to work or none of the other solution for example 2018-02-31 is seen as a valid date – Tobi Owolawi Dec 15 '20 at 15:17
  • 4
    The question was asked about *javascript* not Typescript. The built-in typings for `isNaN` only include the "correct" argument type (i.e. `number`), not types that can be trivially coerced to the correct type (like `string` or `Date`). The whole *point* of Typescript is to avoid the kind of fast-and-loose reckless behavior that the JS runtime lets you get away with. (IMHO the best way to convey intent is `isNan(d.getTime())`.) – Coderer Jan 27 '21 at 09:35
  • 3
    The function returns valid date for any date that has a day number less than 32. So `2021-02-30` is valid date `2021-04-31` is also a valid date !! – Mohsen Alyafei Feb 11 '21 at 07:49
  • 1
    doesn't work. It says 02/30/2001 is a valid date – john k Apr 01 '21 at 12:10
  • in plain javascript (in a browser console), I put up this simple code: – Manik Mittal Jan 31 '22 at 15:55
  • In plain Javascript (in Chrome Console), I put this simple Javascript code: var dateVar = new Date('02/31/2022'); // an invalid date var isInvalid =(isNaN(date.valueOf())); Now, if I try to get value of isInvalid, it is coming as false. For some reason, the value for dateVar variable is equated as Mar 03, 2022. Any ideas? – Manik Mittal Jan 31 '22 at 15:59
  • `isNaN (new Date ('2021-02-30'))` returns `true` so @MohsenAlyafei it seems that there is a bug in the JS engine that you use. I bet you it is V8! – dotnetCarpenter Oct 27 '22 at 13:46
  • I ran a benchmark on both versions and the longer version (with `prototype.toString`) was only 8% slower than the shorter version. 16mm ops/sec vs 17.4mm ops/sec. Got the same results using a valid `Date` and `'Invalid Date'` `Date` as inputs. – RcoderNY Aug 07 '23 at 07:33
351

Instead of using new Date() you should use:

var timestamp = Date.parse('foo');

if (isNaN(timestamp) == false) {
  var d = new Date(timestamp);
}

Date.parse() returns a timestamp, an integer representing the number of milliseconds since 01/Jan/1970. It will return NaN if it cannot parse the supplied date string.

Yves M.
  • 29,855
  • 23
  • 108
  • 144
Ash
  • 60,973
  • 31
  • 151
  • 169
  • 199
    -1 Dunno why this has so many up votes, `Date.parse` is implementation dependent and definitely not to be trusted to parse general date strings. There is no single format that is parsed correctly in popular browsers, much less all those in use (though eventually the ISO8601 format [specified in ES5](http://es5.github.com/#x15.9.1.15) should be ok). – RobG May 25 '12 at 02:30
  • 4
    If you use the `new Date('foo')` that's basically equivalent with the `Date.parse('foo')` method. See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#Timestamp_string So what @RobG said, it also applies to it. – golddragon007 Jun 03 '19 at 07:52
  • 6
    This test would fail in Chrome. For example, Date.parse('AAA-0001') in Chrome gives me a number. – Nick Jun 17 '19 at 04:28
  • 2
    failed ... detect all numeric values – mercury Nov 23 '19 at 22:42
  • Needs the American MM/DD/YYYY format to work. `Date.parse('24/12/2021')` returns `NaN`. – Jan Werkhoven May 24 '21 at 02:26
  • seriously, a "== false" in if statement? – Human programmer May 13 '22 at 18:40
  • Quite problematic if we test it on legitimate inputs for `new Date()`, such as `Date.now()` or `.toLocaleTimeString`. I would prefer this: `isNaN(new Date(Date.now()).getTime())` – Tzahi Leh Jun 19 '22 at 20:08
125

You can check the validity of a Date object d via

d instanceof Date && isFinite(d)

To avoid cross-frame issues, one could replace the instanceof check with

Object.prototype.toString.call(d) === '[object Date]'

A call to getTime() as in Borgar's answer is unnecessary as isNaN() and isFinite() both implicitly convert to number.

Community
  • 1
  • 1
Christoph
  • 164,997
  • 36
  • 182
  • 240
  • Try this in chrome - Object.prototype.toString.call(new Date("2013-07-09T19:07:9Z")). It will return "[object Date]". According to you, therefore, "2013-07-09T19:07:9Z", should be a valid date. But it is not. You can verify it, again in chrome, by doing var dateStr = new Date("2013-07-09T19:07:9Z"); dateStr It will return invalid date. – Tintin Jul 18 '13 at 00:06
  • 2
    @Tintin: that's what `isFinite()` is for - `toString.call()` is only a replacement for the `instanceof` part of the check – Christoph Jul 18 '13 at 05:25
  • Will comparing with '[object Date]' work with non-english browsers? I doubt it. – kristianp May 08 '15 at 01:04
  • 2
    @kristianp actually it probably will and is probably even part of the ECMAScript spec. But, yes, it seems ugly. – binki Dec 11 '15 at 06:36
  • To me the first approach here is the very best option, although I'm not sure if there's any real-world advantage of using `isFinite` over `isNaN` (both work just fine with `Date(Infinity)`). Furthermore, if you want the opposite condition, it gets a bit simpler: `if (!(date instanceof Date) || isNaN(date))`. – Andrew Jan 30 '18 at 01:33
  • isFinite() expects a number but you already made sure d is an Date object. So your code not correct syntax and makes no sense, too. – Mick Feb 21 '19 at 12:23
  • @Mick—not sure what your point is. `let d = new Date(NaN)` creates a valid *Date* object, but it represents an invalid date, so `d instanceof Date` returns true and but `isFinite(d)` returns `false`. – RobG Nov 04 '21 at 22:42
  • If you would use TypeScript you would know that isFinite() requires a number but you actually put in a Date object. This might be catched by some browsers but actually it is incorrect and may result in an error. Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite – Mick Nov 05 '21 at 12:40
111

shortest answer to check valid date

if(!isNaN(date.getTime()))
abhirathore2006
  • 3,317
  • 1
  • 25
  • 29
  • 6
    The only problem is if date is not of type Date; you get a JS error. – Andrew Jan 30 '18 at 01:28
  • @Andrew you need to create the date Object and if you already have an object then use `date && !isNaN(date.getTime())` – abhirathore2006 Jan 31 '18 at 05:14
  • That still gives you a JS error if `date` is not of type Date. For example: `var date = 4; date && !isNaN(date.getTime());`. – Andrew Jan 31 '18 at 15:29
  • @Andrew use `date instanceof Date && !isNaN(date.getTime())` – abhirathore2006 Feb 01 '18 at 15:49
  • 5
    Right, like the other answers from 8 years ago. :P https://stackoverflow.com/a/1353945/2321042 – Andrew Feb 01 '18 at 17:13
  • 1
    doesn't work as intended, i can enter date as 60/80/9000 and it returns `Thu Oct 30 9006 00:00:00 GMT+0000 (Greenwich Mean Time)` as the date? – blueprintchris Jun 24 '18 at 19:35
  • 4
    As long as they're using `var date = new Date(str)`, then this answer would be the shortest and most appropriate. – Mark Entingh Jan 28 '19 at 01:04
  • `!isNaN(new Date('BLA-45353').getTime())` logs `true` – cmgchess Jul 22 '22 at 14:16
  • I don't understand all those commenters about the Date type and how this fails with some string inputs: the question was about testing **Date instances**, not about how strange strings can sometime produce valid Date instances. Please read the question. – trincot Feb 22 '23 at 09:52
103

My solution is for simply checking whether you get a valid date object:

Implementation

Date.prototype.isValid = function () {
    // An invalid date object returns NaN for getTime() and NaN is the only
    // object not strictly equal to itself.
    return this.getTime() === this.getTime();
};  

Usage

var d = new Date("lol");

console.log(d.isValid()); // false

d = new Date("2012/09/11");

console.log(d.isValid()); // true
Ash Clarke
  • 4,807
  • 1
  • 37
  • 48
  • 40
    `isNaN` is a more explicit way to test for NaN – orip Sep 11 '12 at 17:16
  • 1
    And yet, you always find people writing their own versions :) http://documentcloud.github.com/underscore/docs/underscore.html#section-106 – Ash Clarke Sep 12 '12 at 09:00
  • 4
    since I respect underscore.js this prompted some research. `isNaN("a") === true`, while `("a" !== "a") === false`. It's worth thinking about. +1 – orip Sep 12 '12 at 09:14
  • 9
    I tested the performance for the 3 main solutions I have found here. Congrats, you are the winner! http://jsperf.com/detecting-an-invalid-date – zVictor Jul 25 '14 at 09:40
  • Fails for me for `new Date(null)` – Jashwant Nov 17 '14 at 07:38
  • It is a valid date. In the spec, http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.3.2, it says if `value` (i.e. `new Date(value)`) is a string, parse `value` as a date as per `Date.parse()`. If it is not a string, it does a coercion to a Number. When you coerce `null` or `""` to a number, you get `0`. When you do `new Date(0)` you get a valid Date object that represents the Unix epoch. You can avoid this by wrapping the `isValid` call with an `if (date) {` condition, or simply `date && date.isValid()`. – Ash Clarke Nov 17 '14 at 11:54
  • 1
    Fails for this: (new Date("02-31-2000")).isValid() – Ali Salehi Jun 03 '16 at 05:21
  • 2
    @Ali That is a valid date object. `new Date("02-31-2000") // Thu Mar 02 2000 00:00:00 GMT+0000 (GMT Standard Time)`. If you are passing in a string to the date constructor, you must pass in a standardised string to get a reliable result. Specifically, "The string should be in a format recognized by the Date.parse() method". https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date – Ash Clarke Jun 03 '16 at 09:33
  • 1
    @AshClarke @orip in this context, getTime() always returns a number. No gotchas, so `isNaN()` is indeed better here – André Werlang Jan 13 '18 at 00:04
  • @AndréWerlang - Which context? NaN may be a number, but it's not strictly equal to itself. "better" is subjective; After all, this answer is over 5 years old. – Ash Clarke Jan 15 '18 at 16:46
  • 1
    @AshClarke in this context (of a Date value), both `d.getTime() === d.getTime()` and `isNaN(d.getTime())` lead to the same result, always. So with `isNaN` people reading this code would think a specific case is handled, which doesn't look crazy. People would have a hard time even to make a google search on the comparison approach. You decided to use commends to give people a hint. I prefer explicit code. – André Werlang Jan 15 '18 at 17:35
  • Eslint does not like this solution: https://eslint.org/docs/latest/rules/no-self-compare. – RdC1965 Nov 25 '22 at 12:49
56

I have seen some answers that came real close to this little snippet.

JavaScript way:

function isValidDate(dateObject){
    return new Date(dateObject).toString() !== 'Invalid Date';
}
console.log(isValidDate('WTH')); // -> false
console.log(isValidDate(new Date('WTH'))); // -> false
console.log(isValidDate(new Date())); // -> true

ES2015 way:

const isValidDate = dateObject => new Date(dateObject)
    .toString() !== 'Invalid Date';
console.log(isValidDate('WTH')); // -> false
console.log(isValidDate(new Date('WTH'))); // -> false
console.log(isValidDate(new Date())); // -> true
Mike
  • 14,010
  • 29
  • 101
  • 161
Jason Foglia
  • 2,414
  • 3
  • 27
  • 48
  • 2
    Not sure if I'm missing something but Isn't doing new Date() twice pointless? – Jon Catmull Nov 13 '19 at 10:17
  • 9
    The latter has *nothing* to do with TypeScript. It is perfectly valid JS. – hackel Dec 31 '19 at 16:09
  • 2
    Passing any value that the Date constructor can convert to a valid Date object is treated as a valid date, e.g. `isValidDate(0)` and `isValidDate(['0'])` return true. – RobG Jun 06 '21 at 13:38
  • @RobG you are correct about isValidDate(0) but isValidDate(['0']) comes back false. zero is convertable to new Date(0) and is valid. – Jason Foglia Jun 07 '21 at 21:16
  • 1
    0 is neither a valid Date object nor is it a valid date. As a timestamp it requires additional information to convert to a date (e.g. epoch and value). Running `isValidDate(['0'])` in your answer returns true. – RobG Jun 07 '21 at 22:40
52

You can simply use moment.js

Here is an example:

var m = moment('2015-11-32', 'YYYY-MM-DD');
m.isValid(); // false

The validation section in the documentation is quite clear.

And also, the following parsing flags result in an invalid date:

  • overflow: An overflow of a date field, such as a 13th month, a 32nd day of the month (or a 29th of February on non-leap years), a 367th day of the year, etc. overflow contains the index of the invalid unit to match #invalidAt (see below); -1 means no overflow.
  • invalidMonth: An invalid month name, such as moment('Marbruary', 'MMMM');. Contains the invalid month string itself, or else null.
  • empty: An input string that contains nothing parsable, such as moment('this is nonsense');. Boolean.
  • Etc.

Source: http://momentjs.com/docs/

R. Oosterholt
  • 7,720
  • 2
  • 53
  • 77
Yves M.
  • 29,855
  • 23
  • 108
  • 144
  • 6
    Best solution, extremely easy to implement , works with any formatting (my case is dd/MM/yyyy), also knows the leap years and doesn't convert invalid dates (i.e. 29/02/2015) into valid ones by itself (i.e. 30/03/2015). To check a date in the formad dd/MM/yyyy I've just had to use `moment("11/06/1986", "DD/MM/YYYY").isValid();` – Rafael Merlin Jul 14 '15 at 14:26
  • 4
    This use of Moment has been deprecated :( – James Sumners Sep 25 '15 at 13:00
  • 2
    Bummer. moment.js still didn't solve my Chrome-specific problem where it guesses ok dates out of phrases. m = moment("bob 2015"); m.isValid(); // true – efreed Nov 03 '15 at 16:27
  • 1
    @JamesSumners how/why? – binki Dec 11 '15 at 06:43
  • @JamesSumners The question is about how to determine whether an object we already know to be a `Date` is in the “invalid” state or not, not whether or not we can use `moment`’s default constructor to implicitly call `Date`’s constructor. – binki Dec 11 '15 at 06:48
  • @binki because they deemed it to be so -- https://github.com/moment/moment/issues/1407 – James Sumners Dec 11 '15 at 15:35
  • @JamesSumners as long as `isValid()` isn’t deprecated, doesn’t matter ;-). – binki Dec 11 '15 at 17:18
  • 2
    This use has not been depreciated. Calling moment(input) without a format string is depreciated (unless the input is ISO formatted). – Chet Feb 16 '16 at 21:35
  • 2
    This method can be extremely slow when processing many dates. Better to use a regex in those cases. – Grid Trekkor Jul 18 '16 at 19:03
  • 2
    @GridTrekkor I'd like to see that as an answer. Don't forget to handle leap years. – André Werlang Jan 16 '18 at 14:49
  • 8
    Usage of moment.js may be simple, but is an enormous overhead. This library is HUGE. I downvoted your answer. – Mick Feb 21 '19 at 12:17
  • 1
    Doesn't work. ```moment('Decimal128', 'YYYY-MM-DD').isValid() // true``` Should be false. – Sam Araiza Jul 09 '19 at 04:51
  • 1
    Worth mentioning - date-fns has an inValid function if you wanted to use something lighter-weight than moment – Ross Coundon Oct 08 '19 at 17:22
  • Introducing a full-blown library for such a simple task that can be done in one line of code is just not a good answer, it is a lazy one. Sorry but I downvoted this. – brielov Jun 29 '21 at 13:01
50

After reading every answer so far, I am going to offer the most simple of answers.

Every solution here mentions calling date.getTime(). However, this is not needed, as the default conversion from Date to Number is to use the getTime() value. Yep, your type checking will complain. :) And the OP cleary knows they have a Date object, so no need to test for that either.

To test for an invalid date:

isNaN(date)

To test for a valid date:

!isNaN(date)

or (thanks to icc97 for this alternative)

isFinite(date) 

or typescript (thanks to pat-migliaccio)

isFinite(+date) 
Steven Spungin
  • 27,002
  • 5
  • 88
  • 78
40

Would like to mention that the jQuery UI DatePicker widget has a very good date validator utility method that checks for format and validity (e.g., no 01/33/2013 dates allowed).

Even if you don't want to use the datepicker widget on your page as a UI element, you can always add its .js library to your page and then call the validator method, passing the value you want to validate into it. To make life even easier, it takes a string as input, not a JavaScript Date object.

See: http://api.jqueryui.com/datepicker/

It's not listed as a method, but it is there-- as a utility function. Search the page for "parsedate" and you'll find:

$.datepicker.parseDate( format, value, settings ) - Extract a date from a string value with a specified format.

Example usage:

var stringval = '01/03/2012';
var testdate;

try {
  testdate = $.datepicker.parseDate('mm/dd/yy', stringval);
             // Notice 'yy' indicates a 4-digit year value
} catch (e)
{
 alert(stringval + ' is not valid.  Format must be MM/DD/YYYY ' +
       'and the date value must be valid for the calendar.';
}

(More info re specifying date formats is found at http://api.jqueryui.com/datepicker/#utility-parseDate)

In the above example, you wouldn't see the alert message since '01/03/2012' is a calendar-valid date in the specified format. However if you made 'stringval' equal to '13/04/2013', for example, you would get the alert message, since the value '13/04/2013' is not calendar-valid.

If a passed-in string value is successfully parsed, the value of 'testdate' would be a Javascript Date object representing the passed-in string value. If not, it'd be undefined.

T J
  • 42,762
  • 13
  • 83
  • 138
Matt Campbell
  • 1,967
  • 1
  • 22
  • 34
  • 3
    Upvote for being the first answer working with non english / locale date formats. – ax. Jul 17 '15 at 16:06
  • The previous comment is incorrect and misleading. The `Date` object in javascript handles date in any locale and a lot of ISO formats (and even some non ISO depending on implementation) – Tofandel Aug 01 '20 at 16:17
33
// check whether date is valid
var t = new Date('2011-07-07T11:20:00.000+00:00x');
valid = !isNaN(t.valueOf());
faridz
  • 729
  • 1
  • 9
  • 9
  • 5
    It's the same [@Borgar wrote](http://stackoverflow.com/a/1353711/505893) 2 years ago... What's new?? – bluish Dec 23 '11 at 13:34
  • 17
    It's two lines instead of ugly nested if statements. – Cypher May 24 '13 at 18:53
  • 2
    Warning: null values passes as valid – wazus Mar 23 '21 at 14:05
  • That doesn't check if the date is valid, it just tests if the built–in parser is able to parse it to a valid Date using whatever implementation specific heuristics it likes. There are many examples where `Date.parse(string)` returns a valid Date object in one implementation and an invalid Date, or different valid Date, in another. – RobG Jun 06 '21 at 13:34
  • This is useful when you know the year, month, and day and check if that specific date exists on a calendar. – Monday Fatigue Jan 31 '23 at 10:19
27

I really liked Christoph's approach (but didn't have enough of a reputation to vote it up). For my use, I know I will always have a Date object so I just extended date with a valid() method.

Date.prototype.valid = function() {
  return isFinite(this);
}

Now I can just write this and it's much more descriptive than just checking isFinite in code...

d = new Date(userDate);
if (d.valid()) { /* do stuff */ }
broox
  • 3,538
  • 33
  • 25
  • 21
    Extending the prototype? That's a big JavaScript no no! – Jasdeep Khalsa Jun 08 '15 at 10:08
  • Upvoting because of the `isFinite` worked for me perfectly. But yes, pointless to extend the prototype. `!isFinite` on a `Date` will catch the fact that the `Date` is `Invalid Date`. Also worth noting my context is inside Node. – Staghouse Nov 09 '19 at 05:38
  • I have not idea why some suggest *isFinite* over *isNaN*, since *isFinite* returns true for a greater range of numbers (-∞ < d < +∞) than a Date object can handle (-8.64e15 < d < +8.64e15) and a Date object with a time value of NaN is explicitly intended to represent an invalid Date. `!isNaN(date)` is more semantic, more accurate and less to type. – RobG Jun 06 '21 at 13:25
23

I use the following code to validate values for year, month and date.

function createDate(year, month, _date) {
  var d = new Date(year, month, _date);
  if (d.getFullYear() != year 
    || d.getMonth() != month
    || d.getDate() != _date) {
    throw "invalid date";
  }
  return d;
}

For details, refer to Check date in javascript

Jingguo Yao
  • 7,320
  • 6
  • 50
  • 63
  • `str` isn't being used. – samus Feb 02 '16 at 18:21
  • ok, now this is genius and as far as I can see the best and only way to validate a crappy date like "Feb 31st 1970". Wish I could give 10 upvotes. – blissweb Sep 02 '21 at 11:40
  • Link is now broken – blissweb Sep 02 '21 at 11:47
  • This answer actually validates the date _value_, not just the date _format_. Only thing I would add is check the value you are passing in for month because in Javascript months are 0-based. You must subtract 1 from the passed-in value to get the correct JS month value. (month = month - 1; before var d = new Date(...) For example, if you pass in "2" to the month parameter in Date(), it will create March. – user0474975 Oct 06 '21 at 18:57
19

you can check the valid format of txDate.value with this scirpt. if it was in incorrect format the Date obejct not instanced and return null to dt .

 var dt = new Date(txtDate.value)
 if (isNaN(dt))

And as @MiF's suggested in short way

 if(isNaN(new Date(...)))
Yuseferi
  • 7,931
  • 11
  • 67
  • 103
15

Too many complicated answers here already, but a simple line is sufficient (ES5):

Date.prototype.isValid = function (d) { return !isNaN(Date.parse(d)) } ;

or even in ES6 :

Date.prototype.isValid = d => !isNaN(Date.parse(d));
Andrew Morton
  • 24,203
  • 9
  • 60
  • 84
Sebastien H.
  • 6,818
  • 2
  • 28
  • 36
  • 1
    From MDN: "The Date.parse() method parses a string representation of a date, and returns the number of milliseconds since January 1, 1970, 00:00:00 UTC or NaN..." So running a potential date through this function returns either an integer or NaN. Then the isNaN() function will give a clean boolean telling you whether the original value was a valid date object or not. This is enough to make a spot check, but the example above then attaches this method to the Date object to make the functionality easily available and readable throughout your program. – Max Wilder Mar 14 '18 at 18:10
  • if d is boolean you will receive 0 or 1 that not is a Nan !! – davcup Mar 26 '19 at 12:26
  • @davcup just tested using `Date.parse(true)`, I correctly get a NaN. – Sebastien H. Jul 02 '19 at 12:24
  • says 02/30/2001 is a valid date :( – john k Apr 01 '21 at 12:14
14

Why am I writing a 48th answer after so many have tried before me? Most of the answers are partly correct and will not work in every situation, while others are unnecessarily verbose and complex. Below is a very concise solution. This will checking if it is Date type and then check if a valid date object:

return x instanceof Date && !!x.getDate();

Now for parsing date Text: Most of the solutions use Date.parse(), or "new Date()" -- both of these will fail certain situations and can be dangerous. JavaScript parses a wide variety of formats and also is dependent on localization. For example, strings like "1" and "blah-123" will parse as a valid date.

Then there are posts that either use a ton of code, or a mile-long RegEx, or use third party frameworks.

This is dead simple method to validate a date string.

function isDate(txt) {
   var matches = txt.match(/^\d?\d\/(\d?\d)\/\d{4}$/); //Note: "Day" in the RegEx is parenthesized
   return !!matches && !!Date.parse(txt) && new Date(txt).getDate()==matches[1];
}
TEST THE FUNCTION
<br /><br />
<input id="dt" value = "12/21/2020">
<input type="button" value="validate" id="btnAction" onclick="document.getElementById('rslt').innerText = isDate(document.getElementById('dt').value)"> 
<br /><br />
Result: <span id="rslt"></span>

The first line of isDate parses the input text with a simple RegEx to validate for date formats mm/dd/yyyy, or m/d/yyyy. For other formats, you will need to change the RegEx accordingly, e.g. for dd-mm-yyyy the RegEx becomes /^(\d?\d)-\d?\d-\d{4}$/

If parse fails, "matches" is null, otherwise it stores the day-of-month. The second lines does more tests to ensure it is valid date and eliminates cases like 9/31/2021 (which JavaScript permits). Finally note the double-whack (!!) converts "falsy" to a boolean false.

Vijay Jagdale
  • 2,321
  • 2
  • 18
  • 16
  • 4
    This says 9/31/2021 and 2/29/2021 are valid dates, but they aren't. – Rokit Oct 25 '21 at 22:56
  • 1
    Good point Rokit! Javascript Date is permissive and allows higher (or lower) numbers and treats higher month-days into the following month(s). So "2/29/2021" is computed as Mar 01 2021. I updated the function to eliminate this issue, and it now checks min/max range including leap year. – Vijay Jagdale Oct 27 '21 at 08:36
  • 2
    Okay, but this only works if the date is in format **mm/dd/yyyy**. If it's in format **yyyy/dd/mm** or **yyyy/mm/dd** then this will return false. – Eliezer Berlin Dec 25 '22 at 10:31
  • @EliezerBerlin, I already mentioned that. You just need to change RegEx accordingly for other date formats. For yyyy/dd/mm, the RegEx is **/^\d{4}/(\d\d)/\d\d$/** For yyyy/mm/dd, it is **/^\d{4}/\d\d/(\d\d)$/** Let me know if that helped. This works for any format but note the "\d\d" part of the RegEx corresponding to "day" portion should be parenthesized – Vijay Jagdale Dec 29 '22 at 20:41
  • @VijayJagdale Thanks! I was concerned that you're hardcoding the format. Though it probably doesn't matter, because you can simply put a hint or tooltip underneath the field saying "The date should be in format MM/DD/YYYY" and users will figure it out. – Eliezer Berlin Dec 30 '22 at 09:33
13

This just worked for me

new Date('foo') == 'Invalid Date'; //is true

However this didn't work

new Date('foo') === 'Invalid Date'; //is false
user1296274
  • 189
  • 2
  • 3
10

None of these answers worked for me (tested in Safari 6.0) when trying to validate a date such as 2/31/2012, however, they work fine when trying any date greater than 31.

So I had to brute force a little. Assuming the date is in the format mm/dd/yyyy. I am using @broox answer:

Date.prototype.valid = function() {
    return isFinite(this);
}    

function validStringDate(value){
    var d = new Date(value);
    return d.valid() && value.split('/')[0] == (d.getMonth()+1);
}

validStringDate("2/29/2012"); // true (leap year)
validStringDate("2/29/2013"); // false
validStringDate("2/30/2012"); // false
Andre Figueiredo
  • 12,930
  • 8
  • 48
  • 74
Dex
  • 12,527
  • 15
  • 69
  • 90
  • (new Date('2/30/2014')).valid() returns true – Andre Figueiredo Jan 31 '14 at 11:39
  • 1
    Been a while since I've answered this but you may need both return conditions, including the `&& value.split('/')[0] == (d.getMonth()+1);` – Dex Jan 31 '14 at 22:22
  • Using `new Date('string date')` is equivalent with `Date.parse('string date')`, see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#Timestamp_string so you might get false true or false values. – golddragon007 Jun 03 '19 at 07:50
10

For Angular.js projects you can use:

angular.isDate(myDate);
Nick Taras
  • 696
  • 8
  • 15
9

I wrote the following solution based on Borgar's solution. Included in my library of auxiliary functions, now it looks like this:

Object.isDate = function(obj) {
/// <summary>
/// Determines if the passed object is an instance of Date.
/// </summary>
/// <param name="obj">The object to test.</param>

    return Object.prototype.toString.call(obj) === '[object Date]';
}

Object.isValidDate = function(obj) {
/// <summary>
/// Determines if the passed object is a Date object, containing an actual date.
/// </summary>
/// <param name="obj">The object to test.</param>

    return Object.isDate(obj) && !isNaN(obj.getTime());
}
Dharman
  • 30,962
  • 25
  • 85
  • 135
Dmytro Shevchenko
  • 33,431
  • 6
  • 51
  • 67
9

I rarely recommend libraries when one can do without. But considering the plethora of answers so far it seems worth pointing out that the popular library "date-fns" has a function isValid. The following documentation is taken from their website:

isValid argument Before v2.0.0 v2.0.0 onward
new Date() true true
new Date('2016-01-01') true true
new Date('') false false
new Date(1488370835081) true true
new Date(NaN) false false
'2016-01-01' TypeError false
'' TypeError false
1488370835081 TypeError true
NaN TypeError false
Carsten Führmann
  • 3,119
  • 4
  • 26
  • 24
6

Date.prototype.toISOString throws RangeError (at least in Chromium and Firefox) on invalid dates. You can use it as a means of validation and may not need isValidDate as such (EAFP). Otherwise it's:

function isValidDate(d)
{
  try
  {
    d.toISOString();
    return true;
  }
  catch(ex)
  {
    return false;    
  }    
}
saaj
  • 23,253
  • 3
  • 104
  • 105
  • 2
    It seems it is the only function that throws an error by ECMA-262 definition. 15.9.5.43 Date.prototype.toISOString ( ) This function returns a String value represent the instance in time represented by this Date object. The format of the String is the Date Time string format defined in 15.9.1.15. All fields are present in the String. The time zone is always UTC, denoted by the suffix Z. If the time value of this object is not a finite Number a RangeError exception is thrown. – Henry Liu Feb 27 '19 at 11:43
4

None of the above solutions worked for me what did work however is

function validDate (d) {
    var date = new Date(d);
    var day = "" + date.getDate();
    if ( day.length == 1 ) day = "0" + day;
    var month = "" + (date.getMonth() + 1);
    if ( month.length == 1 ) month = "0" + month;
    var year = "" + date.getFullYear();
    return (( month + "/" + day + "/" + year ) == d );
}

the code above will see when JS makes 02/31/2012 into 03/02/2012 that it's not valid

Alex
  • 1,457
  • 1
  • 13
  • 26
John
  • 3,512
  • 2
  • 36
  • 53
  • 4
    Ok, but this tests if a string is a date in a M/D/Y format, not "the difference between valid and invalid date objects". It's not really what this is question about. – Borgar Sep 01 '12 at 12:00
  • the reason why its checked against the format is to check if the date has changed after it was parsed – John Sep 10 '12 at 11:29
  • Isn't the OP asking for a method to return a Boolean, not a formatted string? – barrypicker Nov 21 '14 at 20:39
  • 1
    The sample code does return a boolean, the formating plays a part in testing for some of the invalid cases. – John Nov 25 '14 at 11:52
4
IsValidDate: function(date) {
        var regex = /\d{1,2}\/\d{1,2}\/\d{4}/;
        if (!regex.test(date)) return false;
        var day = Number(date.split("/")[1]);
        date = new Date(date);
        if (date && date.getDate() != day) return false;
        return true;
}
4

I've written this function. Pass it a string parameter and it will determine whether it's a valid date or not based on this format "dd/MM/yyyy".

here is a test

input: "hahaha",output: false.

input: "29/2/2000",output: true.

input: "29/2/2001",output: false.

function isValidDate(str) {
    var parts = str.split('/');
    if (parts.length < 3)
        return false;
    else {
        var day = parseInt(parts[0]);
        var month = parseInt(parts[1]);
        var year = parseInt(parts[2]);
        if (isNaN(day) || isNaN(month) || isNaN(year)) {
            return false;
        }
        if (day < 1 || year < 1)
            return false;
        if(month>12||month<1)
            return false;
        if ((month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) && day > 31)
            return false;
        if ((month == 4 || month == 6 || month == 9 || month == 11 ) && day > 30)
            return false;
        if (month == 2) {
            if (((year % 4) == 0 && (year % 100) != 0) || ((year % 400) == 0 && (year % 100) == 0)) {
                if (day > 29)
                    return false;
            } else {
                if (day > 28)
                    return false;
            }      
        }
        return true;
    }
}
Yaseen
  • 598
  • 6
  • 7
3

Date object to string is more simple and reliable way to detect if both fields are valid date. e.g. If you enter this "-------" to the date input field. Some of the above answers won't work.

jQuery.validator.addMethod("greaterThan", 

    function(value, element, params) {
        var startDate = new Date($(params).val());
        var endDate = new Date(value);

        if(startDate.toString() === 'Invalid Date' || endDate.toString() === 'Invalid Date') {
            return false;
        } else {
            return endDate > startDate;
        }
    },'Must be greater than {0}.');
kam
  • 31
  • 2
3

you can convert your date and time to milliseconds getTime()

this getTime() Method return Not a Number NaN when not valid

if(!isNaN(new Date("2012/25/255").getTime()))
  return 'valid date time';
  return 'Not a valid date time';
Mina Gabriel
  • 23,150
  • 26
  • 96
  • 124
3

I combined the best performance results I found around that check if a given object:

The result is the following:

function isValidDate(input) {
  if(!(input && input.getTimezoneOffset && input.setUTCFullYear))
    return false;

  var time = input.getTime();
  return time === time;
};
zVictor
  • 3,610
  • 3
  • 41
  • 56
3

This flavor of isValidDate uses a regular expression that handles leap years. It works on regular dates, but not iso ones:

function isValidDate(value) {
  return /((^(10|12|0?[13578])([/])(3[01]|[12][0-9]|0?[1-9])([/])((1[8-9]\d{2})|([2-9]\d{3}))$)|(^(11|0?[469])([/])(30|[12][0-9]|0?[1-9])([/])((1[8-9]\d{2})|([2-9]\d{3}))$)|(^(0?2)([/])(2[0-8]|1[0-9]|0?[1-9])([/])((1[8-9]\d{2})|([2-9]\d{3}))$)|(^(0?2)([/])(29)([/])([2468][048]00)$)|(^(0?2)([/])(29)([/])([3579][26]00)$)|(^(0?2)([/])(29)([/])([1][89][0][48])$)|(^(0?2)([/])(29)([/])([2-9][0-9][0][48])$)|(^(0?2)([/])(29)([/])([1][89][2468][048])$)|(^(0?2)([/])(29)([/])([2-9][0-9][2468][048])$)|(^(0?2)([/])(29)([/])([1][89][13579][26])$)|(^(0?2)([/])(29)([/])([2-9][0-9][13579][26])$))/.test(value)
}

function test(value) {
  console.log(`${value} valid: ${isValidDate(value)}`)
}
<button onClick="test('foo')">foo</button>
<button onClick="test('2/20/2000')">2/20/2000</button>
<button onClick="test('20/2/2000')">20/2/2000</button>
<button onClick="test('2022-02-02T18:51:53.517Z')">2022-02-02T18:51:53.517Z</button>
Seph Reed
  • 8,797
  • 11
  • 60
  • 125
Greg Finzer
  • 6,714
  • 21
  • 80
  • 125
3

A ready function based on top rated answer:

  /**
   * Check if date exists and is valid.
   *
   * @param {String} dateString Date in YYYY-mm-dd format.
   */
  function isValidDate(dateString) {
  var isValid = false;
  var date;

  date =
    new Date(
      dateString);

  if (
    Object.prototype.toString.call(
      date) === "[object Date]") {

    if (isNaN(date.getTime())) {

      // Date is unreal.

    } else {
      // Date is real if month and day match each other in date and string (otherwise may be shifted):
      isValid =
        date.getUTCMonth() + 1 === dateString.split("-")[1] * 1 &&
        date.getUTCDate() === dateString.split("-")[2] * 1;
    }
  } else {
    // It's not a date.
  }

  return isValid;
}
Zon
  • 18,610
  • 7
  • 91
  • 99
3

Simple and elegant solution:

const date = new Date(`${year}-${month}-${day} 00:00`)
const isValidDate = (Boolean(+date) && date.getDate() == day)

sources:

[1] https://medium.com/@esganzerla/simple-date-validation-with-javascript-caea0f71883c

[2] Incorrect date shown in new Date() in JavaScript

Soubriquet
  • 3,100
  • 10
  • 37
  • 52
  • 1
    `date.getDate() == day` is insufficient to determine if the date is valid. The original date format will return an invalid date in some implementations regardless of whether the date is valid or not. Also "1970-01-01 00:00" if parsed correctly will return false (i.e. `Boolean(+new Date("1970-01-01"))` returns false). – RobG Aug 05 '19 at 12:49
  • It will work in Safari if you use the format `const date = new Date(year, month, day);` Note that month is 0 indexed this way so you may have to subtract one to line it up correctly. – Vigrant Feb 24 '20 at 16:26
3

No one has mentioned it yet, so Symbols would also be a way to go:

Symbol.for(new Date("Peter")) === Symbol.for("Invalid Date") // true

Symbol.for(new Date()) === Symbol.for("Invalid Date") // false

console.log('Symbol.for(new Date("Peter")) === Symbol.for("Invalid Date")', Symbol.for(new Date("Peter")) === Symbol.for("Invalid Date")) // true

console.log('Symbol.for(new Date()) === Symbol.for("Invalid Date")', Symbol.for(new Date()) === Symbol.for("Invalid Date")) // false

Be aware of: https://caniuse.com/#search=Symbol

Stefan Rein
  • 8,084
  • 3
  • 37
  • 37
3

Inspired by Borgar's approach I made sure that the code not only validates the date, but actually makes sure the date is a real date, meaning that dates like 31/09/2011 and 29/02/2011 are not allowed.

function(dateStr) {
  s = dateStr.split('/');
  d = new Date(+s[2], s[1] - 1, +s[0]);
  if (Object.prototype.toString.call(d) === "[object Date]") {
    if (!isNaN(d.getTime()) && d.getDate() == s[0] &&
      d.getMonth() == (s[1] - 1)) {
      return true;
    }
  }
  return "Invalid date!";
}
Raz
  • 595
  • 4
  • 16
  • But... methods above (@Borgar's and the others) already checks for this type of validity... I can't get the issue. – bluish Dec 23 '11 at 13:30
  • Borgar's doesn't - see his own comment to his answer. – EML Dec 29 '13 at 22:09
  • 1
    This solution only works when your country uses the `dd/MM/yyyy` notation. Also, it returns `true` when it's valid & `'Invalid date!'` if it's not, better return 1 type only. – A1rPun Dec 22 '15 at 10:00
2

For int 1-based components of a date:

var is_valid_date = function(year, month, day) {
    var d = new Date(year, month - 1, day);
    return d.getFullYear() === year && (d.getMonth() + 1) === month && d.getDate() === day
};

Tests:

    is_valid_date(2013, 02, 28)
&&  is_valid_date(2016, 02, 29)
&& !is_valid_date(2013, 02, 29)
&& !is_valid_date(0000, 00, 00)
&& !is_valid_date(2013, 14, 01)
Denis Ryzhkov
  • 2,321
  • 19
  • 12
2

The selected answer is excellent, and I'm using it as well. However, if you're looking for a way to validate user date input, you should be aware that the Date object is very persistent about making what might appear to be invalid construction arguments into valid ones. The following unit test code illustrates the point:

QUnit.test( "valid date test", function( assert ) {
  //The following are counter-examples showing how the Date object will 
  //wrangle several 'bad' dates into a valid date anyway
  assert.equal(isValidDate(new Date(1980, 12, 15)), true);
  d = new Date();
  d.setFullYear(1980);
  d.setMonth(1);
  d.setDate(33);
  assert.equal(isValidDate(d), true);
  assert.equal(isValidDate(new Date(1980, 100, 150)), true);
  //If you go to this exterme, then the checker will fail
  assert.equal(isValidDate(new Date("This is junk")), false);
  //This is a valid date string
  assert.equal(isValidDate(new Date("November 17, 1989")), true);
  //but is this?
  assert.equal(isValidDate(new Date("November 35, 1989")), false);  
  //Ha!  It's not.  So, the secret to working with this version of 
  //isValidDate is to pass in dates as text strings... Hooboy
  //alert(d.toString());
});
dolphus333
  • 1,232
  • 1
  • 13
  • 18
2
function isValidDate(strDate) {
    var myDateStr= new Date(strDate);
    if( ! isNaN ( myDateStr.getMonth() ) ) {
       return true;
    }
    return false;
}

Call it like this

isValidDate(""2015/5/2""); // => true
isValidDate(""2015/5/2a""); // => false
kiranvj
  • 32,342
  • 7
  • 71
  • 76
2

NaN is falsy. invalidDateObject.valueOf() is NaN.

const d = new Date('foo');
if (!d.valueOf()) {
  console.error('Not a valid date object');
}
else {
  // act on your validated date object
}

Even though valueOf() is functionally equivelant to getTime(), I feel it's more appropriate in this context.

Jordan Szymczyk
  • 65
  • 1
  • 1
  • 7
1

Generally I'd stick with whatever Date implantation is in the browser stack. Which means you will always get "Invalid Date" when calling toDateString() in Chrome, Firefox, and Safari as of this reply's date.

if(!Date.prototype.isValidDate){
  Date.prototype.isValidDate = function(){
    return this.toDateString().toLowerCase().lastIndexOf('invalid') == -1;
  };
}

I did not test this in IE though.

pixelbacon
  • 31
  • 5
1
function isValidDate(date) {
  return !! (Object.prototype.toString.call(date) === "[object Date]" && +date);
}
Ryan Ransford
  • 3,224
  • 28
  • 35
Joel Kornbluh
  • 1,437
  • 1
  • 13
  • 17
  • 3
    Please edit this to provide some more background/explanation of the various bits of "magic" that you're performing. – Ryan Ransford Apr 23 '15 at 17:46
  • consider +date as date.toNumber ( actually there is no .toNumber method ) and parseInt(date) !== +date, parseInt(date) === NaN. "+" operator is a magic in js. and not cross-browser: try this: [new Date(Date.now()) + 1, +new Date(Date.now()) + 1] – Abdullah Jan 11 '16 at 16:13
1

So I liked @Ask Clarke answer with little improvement by adding try catch block for dates which cannot go through var d = new Date(d) -

function checkIfDateNotValid(d) {
        try{
            var d = new Date(d);
            return !(d.getTime() === d.getTime()); //NAN is the only type which is not equal to itself.
        }catch (e){
            return true;
        }

    }
Saurabh Gupta
  • 363
  • 3
  • 6
  • 17
  • Which input would make it throw? It seems like anything can be put into the Date constructor? – Esben Skov Pedersen Apr 26 '17 at 04:15
  • @Esben Skove Pedersen - I dont know exactly maybe from back end, I am using aui-datepicker input element to get date. Format is yy-mm-dd, when i change it to yy-dd-mm it just throws error. By using try catch I was able to get what I want so did not dig any deeper. – Saurabh Gupta Apr 26 '17 at 18:55
1

Yet another way to check whether the date is a valid date object:

const isValidDate = (date) => 
  typeof date === 'object' && 
  typeof date.getTime === 'function' && 
  !isNaN(date.getTime())
iwatakeshi
  • 697
  • 3
  • 17
  • 31
1

I have a solution.

const isInvalidDate = (dateString) => JSON.stringify(new Date(dateString)) === 'null';

const invalidDate = new Date('Hello');
console.log(isInvalidDate(invalidDate)); //true

const validDate = new Date('2021/02/08');
console.log(isInvalidDate(validDate)); //false
TylerH
  • 20,799
  • 66
  • 75
  • 101
LocV's Nest
  • 118
  • 1
  • 7
  • if you append any number at the end of invalid date string it will become valid for ex: const invalidDate = new Date('Hello-09'); // Sat Sep 01 2001 00:00:00 GMT+0530 (India Standard Time) then the above solution will fail. – spratap124 Jul 28 '22 at 06:28
1

I think some of this is a long process. We can cut it short as shown below:

 function isValidDate(dateString) {
        debugger;
        var dateStringSplit;
        var formatDate;

        if (dateString.length >= 8 && dateString.length<=10) {
            try {
                dateStringSplit = dateString.split('/');
                var date = new Date();
                date.setYear(parseInt(dateStringSplit[2]), 10);
                date.setMonth(parseInt(dateStringSplit[0], 10) - 1);
                date.setDate(parseInt(dateStringSplit[1], 10));

                if (date.getYear() == parseInt(dateStringSplit[2],10) && date.getMonth()+1 == parseInt(dateStringSplit[0],10) && date.getDate() == parseInt(dateStringSplit[1],10)) {
                    return true;
                }
                else {
                    return false;
                }

            } catch (e) {
                return false;
            }
        }
        return false;
    }
agf
  • 171,228
  • 44
  • 289
  • 238
user889209
  • 35
  • 1
  • 3
    The question asked for how to find invalid Date instances, not strings, and besides: who says a date can't be delimited by something other than a forward-slash? – jrz Dec 21 '12 at 22:22
  • why write 2 lines of code when you can write 25 – Tom Hoffman Feb 07 '22 at 15:08
1

With date FNS there is the function called isExists(). It check if the date exists (Feb 31 is not supposed to exist).

Examples:

// For the valid date:
const result = isExists(2018, 0, 31)
//=> true
// For the invalid date:
const result = isExists(2018, 1, 31) 
//=> false

Documentation: https://date-fns.org/v2.30.0/docs/isExists

Alan
  • 9,167
  • 4
  • 52
  • 70
1

Only a few people here (@Zen, @Dex, @wanglab...) counts with a javascript tolerance of overflowing the day number in months like February, April, June, etc...

If you specify which format you would like to handle (i.e. yyyy-MM-dd), then you do not have to use the javascript object Date at all in your solution.

function leapYear(year) {
    return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}

function validateDateStr(dateStr) {

    if (/^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]$/.test(dateStr) === false) {
        return false;
    }

    var m = parseInt(dateStr.substr(5, 2));
    var d = parseInt(dateStr.substr(8, 2));
    var y = parseInt(dateStr.substr(0, 4));

    // you can add a year check for a value greater than let's say 5000 :-D

    if (m > 12 || d > 31) {
        return false;
    } else if (m == 2 && d > 28) {
        if (d == 29) {
            if (!leapYear(y)) {
                return false;
            }
        } else {
            return false;
        }
    } else if (d > 30 && (m == 4 || m == 6 || m == 9 || m == 11)) {
        return false;
    }

    return true;
}

console.log("2020-02-29:" + validateDateStr("2020-02-29")); // true
console.log("2020-02-30:" + validateDateStr("2020-02-30")); // false
console.log("2022-02-29:" + validateDateStr("2022-02-29")); // false
console.log("2021-02-28:" + validateDateStr("2021-02-28")); // true
console.log("2020-03-31:" + validateDateStr("2020-03-31")); // true
console.log("2020-04-30:" + validateDateStr("2020-04-30")); // true
console.log("2020-04-31:" + validateDateStr("2020-04-31")); // false
console.log("2020-07-31:" + validateDateStr("2020-07-31")); // true
console.log("2020-07-32:" + validateDateStr("2020-07-32")); // false
console.log("2020-08-31:" + validateDateStr("2020-08-31")); // true
console.log("2020-12-03:" + validateDateStr("2020-12-03")); // true
console.log("2020-13-03:" + validateDateStr("2020-13-03")); // false
console.log("0020-12-03:" + validateDateStr("0020-12-03")); // true
//invalid regex
console.log("20-12-03:" + validateDateStr("20-12-03")); // false
console.log("2020-012-03:" + validateDateStr("2020-012-03")); // false
console.log("2020-12-003:" + validateDateStr("2020-12-003")); // false
Petr Kloza
  • 43
  • 7
0
var isDate_ = function(input) {
        var status = false;
        if (!input || input.length <= 0) {
          status = false;
        } else {
          var result = new Date(input);
          if (result == 'Invalid Date') {
            status = false;
          } else {
            status = true;
          }
        }
        return status;
      }
Dhayalan
  • 57
  • 2
0

This function validates a string date in digit formats delimited by a character, e.g. dd/mm/yyyy, mm/dd/yyyy

/*
Param  : 
1)the date in string data type 
2)[optional - string - default is "/"] the date delimiter, most likely "/" or "-"
3)[optional - int - default is 0] the position of the day component when the date string is broken up via the String.split function (into arrays)
4)[optional - int - default is 1] the position of the month component when the date string is broken up via the String.split function (into arrays)
5)[optional - int - default is 2] the position of the year component when the date string is broken up via the String.split function (into arrays)

Return : a javascript date is returned if the params are OK else null
*/
function IsValidDate(strDate, strDelimiter, iDayPosInArray, iMonthPosInArray, iYearPosInArray) {
    var strDateArr; //a string array to hold constituents day, month, and year components
    var dtDate; //our internal converted date
    var iDay, iMonth, iYear;


    //sanity check 
    //no integer checks are performed on day, month, and year tokens as parsing them below will result in NaN if they're invalid
    if (null == strDate || typeof strDate != "string")
        return null;

    //defaults
    strDelimiter = strDelimiter || "/";
    iDayPosInArray = undefined == iDayPosInArray ? 0 : iDayPosInArray;
    iMonthPosInArray = undefined == iMonthPosInArray ? 1 : iMonthPosInArray;
    iYearPosInArray = undefined == iYearPosInArray ? 2 : iYearPosInArray;

    strDateArr = strDate.split(strDelimiter);

    iDay = parseInt(strDateArr[iDayPosInArray],10);
    iMonth = parseInt(strDateArr[iMonthPosInArray],10) - 1; // Note: months are 0-based
    iYear = parseInt(strDateArr[iYearPosInArray],10);

    dtDate = new Date(
        iYear,
        iMonth, // Note: months are 0-based
        iDay);

    return (!isNaN(dtDate) && dtDate.getFullYear() == iYear && dtDate.getMonth() == iMonth && dtDate.getDate() == iDay) ? dtDate : null; // Note: months are 0-based
}

Example call:

var strDate="18-01-1971";

if (null == IsValidDate(strDate)) {

  alert("invalid date");
}
Suhas Bachhav
  • 403
  • 1
  • 7
  • 28
wanglabs
  • 57
  • 4
0
Date.valid = function(str){
  var d = new Date(str);
  return (Object.prototype.toString.call(d) === "[object Date]" && !isNaN(d.getTime()));
}

https://gist.github.com/dustinpoissant/b83750d8671f10c414b346b16e290ecf

Dustin Poissant
  • 3,201
  • 1
  • 20
  • 32
0

Try something like this:

if (!('null' === JSON.stringify(new Date('wrong date')))) console.log('correct');
else console.log('wrong');
TylerH
  • 20,799
  • 66
  • 75
  • 101
iClyde
  • 26
  • 3
0

If you use io-ts, you can use the decoder DateFromISOString directly.

import { DateFromISOString } from 'io-ts-types/lib/DateFromISOString'

const decoded = DateFromISOString.decode('2020-05-13T09:10:50.957Z')
duan
  • 8,515
  • 3
  • 48
  • 70
0

Pure JavaScript solution:

const date = new Date(year, (+month-1), day);
const isValidDate = (Boolean(+date) && date.getDate() == day);

Also works on leap years!

Credit to https://medium.com/@esganzerla/simple-date-validation-with-javascript-caea0f71883c

S. Esteves
  • 415
  • 4
  • 14
  • Why Boolean(+date) and not Boolean(Number(date)) or !!+date? And it won't work on 0. – s123 May 09 '23 at 13:08
0

Here I came up with a solution that might be helpful for those looking for a test function that can check whether it's given yyyy/mm/dd or mm/dd/yyyy also with serveral symbols such as '/', '-', '.'.

function isValidDate(dateString) {
    // Regular expression pattern for mm/dd/yyyy format
    const regTestUsa = /^(0?[1-9]|1[0-2])[\/.-](0?[1-9]|1\d|2\d|3[01])[\/.-](\d{2}|\d{4})$/;
    // Regular expression pattern for yyyy/mm/dd format
    const regTestUNiv = /^(\d{2}|\d{4})[\/.-](0?[1-9]|1[0-2])[\/.-](0?[1-9]|1\d|2\d|3[01])$/;
    const regTestYear = /^(\d{2}|\d{4})$/;

    let USAformat = ''
    let Univformat = ''
    
    if (regTestUNiv.test(dateString)) {
        Univformat = dateString
    } else if (regTestUsa.test(dateString)){
        USAformat = dateString
    } else {
        return dateString instanceof Date && !isNaN(dateString);
    }

    let year = '';
    let month = '';
    let day = '';
    
    if (USAformat.length > 0){
         [month,day,year] = USAformat.split(/[\/.-]/);
    } else if(Univformat.length > 0){
         [year,month,day] = Univformat.split(/[\/.-]/)
    }

    const parsedYear = parseInt(year, 10);
    if (parsedYear < 100) {
        // Adjust 2-digit year to 4-digit year
        const currentYear = new Date().getFullYear();
        const currentCentury = Math.floor(currentYear / 100) * 100;
        const adjustedYear = currentCentury + parsedYear;

        if (!regTestYear.test(adjustedYear)) {
            return false;
        }
    }

    const date = new Date(year, month - 1, day);
    if (isNaN(date.getTime())) {
        return false;
    }

    const parsedMonth = date.getMonth() + 1;
    const parsedDay = date.getDate();

    return (
        parseInt(month, 10) === parsedMonth &&
        parseInt(day, 10) === parsedDay
    );
}

you can test codes with the followings:

// Is the date valid Date object
console.log(isValidDate(new Date()), "T")

// Does the date start with 0 for month and/or day 
console.log(isValidDate('2023.01.21'),"T") // true
console.log(isValidDate('2023.01.09'),"T") // true
console.log(isValidDate('2023.1.09'),"T") // true

// Is the date divided by valid symble
console.log(isValidDate('2023/12/31'),"T")  // true
console.log(isValidDate('2023-12-31'),"T") // true
console.log(isValidDate('2023.12.31'),"T") // true
console.log(isValidDate('2023?12.31'),"F") // false

// Is the date formatted in USA 
console.log(isValidDate('12/31/2050'),"T") // true
console.log(isValidDate('12/31/50'),"T") // true

// Is the date out of range
console.log(isValidDate('2023.2.29'),"F")  // false
console.log(isValidDate('2023.14.29'),"F")  // false
console.log(isValidDate('2023.01.32'),"F") // false

//other test
console.log(isValidDate('12/0/0'),"F")
console.log(isValidDate('0/0/0'),"F")
console.log(isValidDate('/120/0'),"F")
console.log(isValidDate('boo'),"F")
console.log(isValidDate('124'),"F")
 
Hoyeon Kim
  • 33
  • 4
0
const isDate = (str) => String(new Date(str)) !== 'Invalid Date'

so tonight i'm gonna party up to isDate('12/31/999999')

starball
  • 20,030
  • 7
  • 43
  • 238
King Friday
  • 25,132
  • 12
  • 90
  • 84
-1

date.parse(valueToBeTested) > 0 is all that's needed. A valid date will return the epoch value and an invalid value will return NaN which will fail > 0 test by virtue of not even being a number.

This is so simple that a helper function won't save code though it might be a bit more readable. If you wanted one:

String.prototype.isDate = function() {
  return !Number.isNaN(Date.parse(this));
}

OR

To use:

"StringToTest".isDate();
rainabba
  • 3,804
  • 35
  • 35
  • 1
    '1970-01-01T00:00:00Z' is a valid date yet fails your check. – Westy92 Aug 02 '17 at 15:34
  • Calling that a "valid date" is pedantic at best and wrong at worse since without added precicion, that is the 0 moment of the epoch [] time. That system was designed to track every second (though the JS implementation is milisecond based so you have to multiply accordingly) after the clock started. By definition, you cannot record the time a clock starts because there's no reference. So... if you want to be pedantic, yes. In reality, no. In JS, the first valid date IS "1970-01-01T00:00:00.001Z" (the first millisecond since that clock started tracking time). – rainabba Aug 03 '17 at 17:14
  • 3
    @rainabba, first I would recommend [ECMAScript Language Specification, Time Values and Time Range](http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.1) and [The Humble Programmer](https://www.cs.utexas.edu/~EWD/transcriptions/EWD03xx/EWD340.html). Next, an improvement could be to change `return Data.parse( this );` to `return !Number.isNaN(Data.parse(this));` – Bjørn Egil Feb 06 '18 at 17:03
  • 2
    @BjørnEgil it should be "Date", not "Data" – mu4ddi3 Jul 12 '18 at 11:28
-1

Why i Suggest moment.js

it is very popular library

simple to solve all date and time,format,timezone problems

easy to check string date valid or not

var date = moment("2016-10-19");
date.isValid()

we can't solve simple way to validate all the cases

Disspointment

if i insert in valid number like 89,90,95 in new Date() above few answare , i am getting bad result however it return true

const isValidDate = date => { 
console.log('input'+date)
var date=new Date(date);

console.log(date)
return !! (Object.prototype.toString.call(date) === "[object Date]" && +date)
//return !isNaN(date.getTime())
}


var test="05/04/2012"
console.log(isValidDate(test))



var test="95"
console.log(isValidDate(test))



var test="89"
console.log(isValidDate(test))



var test="80"
console.log(isValidDate(test))



var test="badstring"
console.log(isValidDate(test))
Balaji
  • 9,657
  • 5
  • 47
  • 47