views:

3577

answers:

3

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?

EDIT - thanks for the responses!

  • 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.

EDIT 2

  • 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 (section 15.9.5.9) and this behavior is in the standard, which is exactly what I'm looking for.

My final function, based on Borgar's solution:

function isValidDate(d) {
  if ( Object.prototype.toString.call(d) !== "[object Date]" )
    return false;
  return !isNaN(d.getTime());
}
+6  A: 

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.

Ash
+1, very nice, thanks! Date.parse returns milliseconds, not a Date object, so after the test we still need to construct a Date object from it (new Date(d))
orip
Glad to help, I've edited the answer to make it clearer that Date.parse returns a timestamp in millisecond.
Ash
+4  A: 

Here's how I would do it:

if ( Object.prototype.toString.call(d) === "[object Date]" ) {
  // it is a date
  if ( isNaN( d.getTime() ) ) {  // d.valueOf() could also work
    // date is not valid
  }
  else {
    // date is valid
  }
}
else {
  // not a date
}
Borgar
Why not "d instanceof Date" for that first comparison instead?
Chris Charabaruk
Chris: "d instance Date" is true for an invalid date as well
orip
instanceof breaks across frames. Duck-typing can work just fine too: validDate == d -- Since the question is for a general utility function I prefer to be more strict.
Borgar
Chris: sorry, I misread your comment, disregard mine.
orip
@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
@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
A: 

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.

Christoph