866

I have an annoying bug in on a webpage:

date.GetMonth() is not a function

So, I suppose that I am doing something wrong. The variable date is not an object of type Date. How can I check for a datatype in Javascript? I tried to add a if (date), but it doesn't work.

function getFormatedDate(date) {
    if (date) {
       var month = date.GetMonth();
    }
}

So, if I want to write defensive code and prevent the date (which is not one) to be formatted, how do I do that?

Thanks!

UPDATE: I don't want to check the format of the date, but I want to be sure that the parameter passed to the method getFormatedDate() is of type Date.

Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129
Martin
  • 39,309
  • 62
  • 192
  • 278

28 Answers28

1489

As an alternative to duck typing via

typeof date.getMonth === 'function'

you can use the instanceof operator, i.e. But it will return true for invalid dates too, e.g. new Date('random_string') is also instance of Date

date instanceof Date

This will fail if objects are passed across frame boundaries.

A work-around for this is to check the object's class via

Object.prototype.toString.call(date) === '[object Date]'
Lukas Liesis
  • 24,652
  • 10
  • 111
  • 109
Christoph
  • 164,997
  • 36
  • 182
  • 240
  • 36
    Out of interest do you know the reason for this failing when passing across frame boundaries? – Simon Lieschke Apr 12 '10 at 06:03
  • 104
    @Simon: JS globals are local to the current global object (aka `window` or `self`); different frames have their own global objects, and their properties (ie globals) refer to distinct objects: `Date` in frame1 is a different function object than `Date` in frame2; the same is true for `Date.prototype`, which is the reason for the `instanceof` failure: `Date.prototype` from frame1 is not part of the prototype chain of `Date` instances from frame2 – Christoph Apr 13 '10 at 16:25
  • 2
    For elaboration on the `instanceof` method failing across frame boundaries, see [JavaScript Garden](http://bonsaiden.github.com/JavaScript-Garden/#types.instanceof) : "... `instanceof` does not work on objects that originate from different JavaScript contexts (e.g. different documents in a web browser), since their constructors will not be the exact same object." – Ollie Bennett Nov 19 '12 at 15:11
  • 10
    Christoph, what do you call "frame"? IFRAME, each frame in FRAMESET or something else (I mean JS-specific, not the HTML-thing)? – Paul Feb 04 '14 at 11:41
  • 5
    @Paul each HTML `frame`/`iframe` has its own JS context, and thus an own `Date` object. You can find all the frames in the [`window.frames`](https://developer.mozilla.org/en-US/docs/Web/API/Window.frames) collection, and the corresponding Date objects via `window.frames[i].window.Date`. For example, try `window.frames[0].window.Date == Date` – user123444555621 Jul 17 '14 at 12:41
  • 23
    `new Date('something') instanceof Date` returns `true` in Chrome. That won't work then. – krillgar Oct 24 '14 at 12:17
  • 2
    @krillgar, I'd argue new Date(/anything/) is an instanceof Date. It's just an invalid instance. – Michael Blackburn Feb 20 '15 at 20:25
  • @MichaelBlackburn I agree that it is an instance of a Date object, but if it's an invalid instance, then how does that help you if you're trying to do anything constructive with it? – krillgar Feb 20 '15 at 20:49
  • 19
    Detecting a Date type object (as opposed to a plain Object or a string) and validating an object you expect to be a Date are two different tasks. There are a number of situations where the input to your function could be one of a number of different data types. In my case, I can trust that any Date object I get is valid (it's not coming straight from a client) If validating is a concern, here is a post with a number of options. http://stackoverflow.com/questions/1353684/detecting-an-invalid-date-date-instance-in-javascript?rq=1 – Michael Blackburn Feb 21 '15 at 03:41
  • FYI Doing something like `date.setUTCHours(0) instanceof Date` will return false but executing it then doing `date instanceof Date` returns true – Kian Aug 11 '15 at 20:48
  • 2
    @Kian that is because `date.setUTCHours(0)` does not return the date object. It returns the number of milliseconds since 1/1/1970 00:00:00 UTC. That value is a number so `date.setUTCHours(0) instanceof Date` will be false. – James Hay Sep 10 '15 at 14:23
  • @Roshdy If you assing any integer to `dateVariable`, then `(new Date(dateVariable) != "Invalid Date")` will evaluate to true. Some strings also can be assigned to this variable in a way that the whole statement evaluates to true. So it doesn't work for what OP wants. – Gui Imamura Jan 19 '16 at 17:17
  • 7
    `Object.prototype.toString.call(new Date('invalid_date')) === '[object Date]'` still returns `true` – Memke Jan 18 '17 at 13:45
  • 1
    'typeof date.getMonth === function' would return true if the object has a getMonth function but it is not really a date. So, there is a small risk there. – heringer Feb 22 '17 at 20:25
  • 3
    even invalid dates have a getMonth function. You can make a small change with: `isNaN(new Date('20171212').getMonth())` if you assume a "real" date always have a month, because then it has to be a number, or it's a NaN – Jan May 12 '18 at 21:50
  • `Object.prototype.toString.call(date) === '[object Date]'` worked well for me, thanks! – csalmeida May 12 '20 at 13:49
194

You can use the following code:

(myvar instanceof Date) // returns true or false
Ren
  • 1,111
  • 5
  • 15
  • 24
SF_dev
  • 2,073
  • 1
  • 12
  • 2
  • 10
    Why is this not the accepted or more upvoted answer? Simply checking if date has a .getMonth property could trigger a false positive. – doremi Dec 04 '13 at 01:17
  • 32
    instanceof can trigger false negatives, see Christoph's comment to his own answer. – Marco Mariani Dec 05 '13 at 14:44
  • 3
    @doremi Here is a demo of `instanceof` triggering false negative: https://jsbin.com/vufufoq/edit?html,js,console – Boghyon Hoffmann Apr 13 '18 at 05:53
  • Since both methods are equally flawed. You have to use @Jan's method in the debate above to make sure `getMonth()` doesn't return NaN on its false positive instance, at least using `instanceof Date` at least *looks* the part. – Darren S Jan 10 '22 at 04:44
  • if I do `new Date("asdf") instanceof Date` it's returning true. – Collin Sep 26 '22 at 18:47
  • 1
    `date instanceof Date && !isNaN(date)` It also checks that it is an instance of a date, and that it is a valid date (each of the tests alone is not completely reliable) – Shlomo Mar 25 '23 at 18:43
119

In order to check if the value is a valid type of the standard JS-date object, you can make use of this predicate:

function isValidDate(date) {
  return date && Object.prototype.toString.call(date) === "[object Date]" && !isNaN(date);
}
  1. date checks whether the parameter was not a falsy value (undefined, null, 0, "", etc..)
  2. Object.prototype.toString.call(date) returns a native string representation of the given object type - In our case "[object Date]". Because date.toString() overrides its parent method, we need to .call or .apply the method from Object.prototype directly which ..
  3. !isNaN(date) finally checks whether the value was not an Invalid Date.
Boghyon Hoffmann
  • 17,103
  • 12
  • 72
  • 170
  • 16
    Wow `isNaN` can be used to check a `Date`. That's some PHP level of inanity. – Nick Nov 19 '19 at 21:04
  • 3
    @Nick a date is a number though. – Josiah Feb 18 '20 at 00:57
  • @Josiah Well, sure, removing all context there's a timestamp there: `typeof Date.now() === "number"`, but: `typeof new Date() === "object"`. More realistically, though, a date is a time and a location in space. – Nick Feb 18 '20 at 20:04
  • 1
    This worked for me in a highly volatile environment where every possibility of string values could exist (actual dates, random letters, blanks, random characters, etc). – Matt Jan 26 '22 at 18:04
40

The function is getMonth(), not GetMonth().

Anyway, you can check if the object has a getMonth property by doing this. It doesn't necessarily mean the object is a Date, just any object which has a getMonth property.

if (date.getMonth) {
    var month = date.getMonth();
}
ZwoRmi
  • 1,093
  • 11
  • 30
Chetan S
  • 23,637
  • 2
  • 63
  • 78
  • 4
    Check whether it's callable: `if (date.getMonth && typeof date.getMonth === "function") {...}` – Aloso Apr 25 '16 at 08:35
28

This is a pretty simple approach if you're not concerned about iframes / other contexts.

// isNaN(Invalid Date) == true
if (date instanceof Date && !isNaN(date)) { // isNaN wont accept a date in typescript, use date.getTime() instead to produce a number
    console.log("is date!");
}
  • Checks if object is actually a Date and not something that looks like one. Any object could have a getMonth function.
  • Ensures the Date is not an Invalid Date
  • Doesn't pass a value into new Date() where a number or even a string could be turned into a Date.

If you need to support iframes and different contexts you can use the accepted answer but add an extra check to identify invalid dates.

// isNaN(Invalid Date) == true
if (Object.prototype.toString.call(date) === '[object Date]' && !isNaN(date)) {
    console.log("is date!");
}

Ryan King
  • 3,538
  • 12
  • 48
  • 72
  • I'm getting this warning: "Argument of type 'Date' is not assignable to parameter of type 'number'"... Do I really need this second check? Indeed, isNaN is for numbers... – Alexander Jan 06 '23 at 23:04
  • Sounds like a typescript issue? You can use `getTime()` to account for this. https://stackoverflow.com/questions/55426680/typescript-isnan-not-accepting-date-object – Ryan King Jan 09 '23 at 03:47
25

As indicated above, it's probably easiest to just check if the function exists before using it. If you really care that it's a Date, and not just an object with a getMonth() function, try this:

function isValidDate(value) {
    var dateWrapper = new Date(value);
    return !isNaN(dateWrapper.getDate());
}

This will create either a clone of the value if it's a Date, or create an invalid date. You can then check if the new date's value is invalid or not.

bdukes
  • 152,002
  • 23
  • 148
  • 175
  • 1
    This worked for me, thanks. However, if you pass a single digit such as 0, or 1, it treats that as a valid Date... any thoughts? – Ricardo Sanchez Jun 23 '15 at 16:16
  • That's right, @RicardoSanchez. You probably want to use the accepted answer (`Object.prototype.toString.call(value) === '[object Date]'`) if it's possible you'll be getting numbers. The method in this answer really tells you whether the `value` is convertible to a `Date`. – bdukes Jun 23 '15 at 20:44
18

For all types I cooked up an Object prototype function. It may be of use to you

Object.prototype.typof = function(chkType){
      var inp        = String(this.constructor),
          customObj  = (inp.split(/\({1}/))[0].replace(/^\n/,'').substr(9),
          regularObj = Object.prototype.toString.apply(this),
          thisType   = regularObj.toLowerCase()
                        .match(new RegExp(customObj.toLowerCase()))
                       ? regularObj : '[object '+customObj+']';
     return chkType
            ? thisType.toLowerCase().match(chkType.toLowerCase()) 
               ? true : false
            : thisType;
}

Now you can check any type like this:

var myDate     = new Date().toString(),
    myRealDate = new Date();
if (myRealDate.typof('Date')) { /* do things */ }
alert( myDate.typof() ); //=> String

[Edit march 2013] based on progressing insight this is a better method:

Object.prototype.is = function() {
        var test = arguments.length ? [].slice.call(arguments) : null
           ,self = this.constructor;
        return test ? !!(test.filter(function(a){return a === self}).length)
               : (this.constructor.name ||
                  (String(self).match ( /^function\s*([^\s(]+)/im)
                    || [0,'ANONYMOUS_CONSTRUCTOR']) [1] );
}
// usage
var Some = function(){ /* ... */}
   ,Other = function(){ /* ... */}
   ,some = new Some;
2..is(String,Function,RegExp);        //=> false
2..is(String,Function,Number,RegExp); //=> true
'hello'.is(String);                   //=> true
'hello'.is();                         //-> String
/[a-z]/i.is();                        //-> RegExp
some.is();                            //=> 'ANONYMOUS_CONSTRUCTOR'
some.is(Other);                       //=> false
some.is(Some);                        //=> true
// note: you can't use this for NaN (NaN === Number)
(+'ab2').is(Number);                 //=> true
KooiInc
  • 119,216
  • 31
  • 141
  • 177
13

UnderscoreJS and Lodash have a function called .isDate() which appears to be exactly what you need. It's worth looking at their respective implementations: Lodash isDate, UnderscoreJs

Stphane
  • 3,368
  • 5
  • 32
  • 47
avalanche1
  • 3,154
  • 1
  • 31
  • 38
13

The best way I found is:

!isNaN(Date.parse("some date test"))
//
!isNaN(Date.parse("22/05/2001"))  // true
!isNaN(Date.parse("blabla"))  // false
jspassov
  • 791
  • 7
  • 11
8

Instead of all the workarounds you can use the following:

dateVariable = new Date(date);
if (dateVariable == 'Invalid Date') console.log('Invalid Date!');

I found this hack better!

itsHarshad
  • 1,519
  • 14
  • 16
  • This does not work unless you put `toString()` after `dateVariable` as an invalid date does not return a string – pbuzz007 Aug 21 '21 at 15:36
6

arrow function

const isValidDate = (value: any) => value instanceof Date && !isNaN(value);

Function:

function isValidDate(d) {
  return d instanceof Date && !isNaN(d);
}
G Clovs
  • 2,442
  • 3
  • 19
  • 24
5

I have been using a much simpler way but am not sure if this is only available in ES6 or not.

let a = {name: "a", age: 1, date: new Date("1/2/2017"), arr: [], obj: {} };
console.log(a.name.constructor.name); // "String"
console.log(a.age.constructor.name);  // "Number"
console.log(a.date.constructor.name); // "Date"
console.log(a.arr.constructor.name);  // "Array"
console.log(a.obj.constructor.name);  // "Object"

However, this will not work on null or undefined since they have no constructor.

mjwrazor
  • 1,866
  • 2
  • 26
  • 42
  • 1
    Any custom made object with the constructor name "Date" returns `"Date"` too which is as risky as just checking if the parameter has `getMonth` property. – Boghyon Hoffmann Jun 27 '17 at 16:11
  • 3
    @boghyon sounds like whomever creates an object with the constructor name of a already predefined Javascript standard library is not following best practices in the first place. That would be like downloading lodash then creating your own lodash module and expecting things to work. – mjwrazor Jun 28 '17 at 13:59
  • note that if the value is `null` then `value.constructor.name` throws an exception. – Ron Klein Aug 31 '21 at 06:11
2

Also you can use short form

function getClass(obj) {
  return {}.toString.call(obj).slice(8, -1);
}
alert( getClass(new Date) ); //Date

or something like this:

(toString.call(date)) == 'Date'
pavlo
  • 460
  • 6
  • 15
2

You could check if a function specific to the Date object exists:

function getFormatedDate(date) {
    if (date.getMonth) {
        var month = date.getMonth();
    }
}
Powerlord
  • 87,612
  • 17
  • 125
  • 175
2

Simply use moment

import moment from 'moment';

moment(myvar).isValid(); //  return true or false
2
const myDate = Date.now(); // 1679252208851
const myDate2 = new Date(); // Sun Mar 19 2023 20:56:59 GMT+0200 (Восточная Европа, стандартное время)

console.log(myDate instanceof Date); // false
console.log(myDate2 instanceof Date); // true

BUT

const myDate3 = new Date(myDate); // Sun Mar 19 2023 20:56:59 GMT+0200 (Восточная Европа, стандартное время)
console.log(myDate3 instanceof Date); // true
1

This function will return true if it's Date or false otherwise:

function isDate(myDate) {
    return myDate.constructor.toString().indexOf("Date") > -1;
} 
Jahid
  • 21,542
  • 10
  • 90
  • 108
1

Yet another variant:

Date.prototype.isPrototypeOf(myDateObject)
Vadim
  • 1,125
  • 8
  • 18
  • Nice and short! But unfortunately, it has the [same issue as `instanceof`](https://jsbin.com/vufufoq/edit?js,console). – Boghyon Hoffmann Apr 13 '18 at 01:00
  • 1
    @BoghyonHoffmann in case of iFrame it may look like: `iWindow.Date.prototype.isPrototypeOf(iWindow.date); // true` `iWindow.date instanceof iWindow.Date; // true` – Vadim Oct 29 '18 at 09:52
1

An approach using a try/catch

function getFormattedDate(date = new Date()) {
  try {
    date.toISOString();
  } catch (e) {
    date = new Date();
  }
  return date;
}

console.log(getFormattedDate());
console.log(getFormattedDate('AAAA'));
console.log(getFormattedDate(new Date('AAAA')));
console.log(getFormattedDate(new Date(2018, 2, 10)));
Ron Klein
  • 9,178
  • 9
  • 55
  • 88
codeKonami
  • 910
  • 9
  • 14
1

with the following approach, you can even check date no to be "Invalid Date"

if(!!date.getDate()){
    console.log('date is valid')
}
Hossein Mousavi
  • 3,118
  • 3
  • 16
  • 35
1

In case you're using Node.js you can check if an object is a Date by using the isDate method of the util module like this.

const util = require('util');

const now = new Date();
console.log(util.types.isDate(now))
0

We can also validate it by below code

var a = new Date();
a.constructor === Date
/*
true
*/

enter image description here

Dino
  • 7,779
  • 12
  • 46
  • 85
Arun
  • 450
  • 3
  • 8
  • The constructor of `function Date() {/*...*/}` is also `Date`. I.e. simply comparing the constructor function is too error-prone which often results in false positives. Bypass user-defined object type with https://stackoverflow.com/a/44198641/5846045 – Boghyon Hoffmann Apr 07 '20 at 11:30
0

Inspired by this answer, this solution works in my case(I needed to check whether the value recieved from API is a date or not):

!isNaN(Date.parse(new Date(YourVariable)))

This way, if it is some random string coming from a client, or any other object, you can find out if it is a Date-like object.

ganjim
  • 1,234
  • 1
  • 16
  • 30
0

Actually date will be of type Object. But you can check if the object has getMonth method and if it is callable.

function getFormatedDate(date) {
    if (date && date.getMonth && date.getMonth.call) {
       var month = date.getMonth();
    }
}
vartec
  • 131,205
  • 36
  • 218
  • 244
  • 2
    Christoph's answer is more accurate. Having a 'call' property doesn't necessarily mean it is a function! – Chetan S Mar 13 '09 at 17:51
0

I had some issues with React hooks where the Date would come in later / lazy loaded and then the initial state can't be null, it won't pass ts checks, but apparently an empty Object does the trick then! :)

const [birthDate, setBirthDate] = React.useState({})

<input
  value={birthDate instanceof Date ? birthDate.toISOString() : ''}
  name="birthDay"
/>
OZZIE
  • 6,609
  • 7
  • 55
  • 59
0

Simplest approach of detecting an valid date.

const isDate = ( str ) => {
    let timestamp = Date.parse( str );
    if (!isNaN(timestamp)) return new Date(timestamp);
    return false
}

console.log( isDate("2020-11-11T12:12:55.123Z") )

console.log( isDate("17/July/2024") )
console.log( "getMonth: ",  isDate("17/July/2024").getMonth() )

console.log( isDate("Invalid something") )
GMKHussain
  • 3,342
  • 1
  • 21
  • 19
  • It looks more like a TryParse than a boolean: will `new Date` in your code ever return "non true" result? – Alexander Jan 10 '23 at 04:31
-1

If you are using Typescript you could check using the Date type:

const formatDate( date: Date ) => {}
Elise Chant
  • 5,048
  • 3
  • 29
  • 36
-4

Couldn't you just use

function getFormatedDate(date) {
    if (date.isValid()) {
       var month = date.GetMonth();
    }
}
Grumpy
  • 2,140
  • 1
  • 25
  • 38