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
.
Invalid Date
: stackoverflow.com/a/44198641/5846045
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]'
You can use the following code:
(myvar instanceof Date) // returns true or false
instanceof
triggering false negative: jsbin.com/vufufoq/edit?html,js,console
getMonth()
doesn't return NaN on its false positive instance, at least using instanceof Date
at least looks the part.
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);
}
date checks whether the parameter was not a falsy value (undefined, null, 0, "", etc..) 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 .. Bypasses user-defined object type with the same constructor name (e.g.: "Date") Works across different JS contexts (e.g. iframes) in contrast to instanceof or Date.prototype.isPrototypeOf. !isNaN(date) finally checks whether the value was not an Invalid Date.
isNaN
can be used to check a Date
. That's some PHP level of inanity.
typeof Date.now() === "number"
, but: typeof new Date() === "object"
. More realistically, though, a date is a time and a location in space.
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();
}
if (date.getMonth && typeof date.getMonth === "function") {...}
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.
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
.
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)) {
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!");
}
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
The best way I found is:
!isNaN(Date.parse("some date test"))
//
!isNaN(Date.parse("22/05/2001")) // true
!isNaN(Date.parse("blabla")) // false
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
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!
toString()
after dateVariable
as an invalid date does not return a string
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.
"Date"
too which is as risky as just checking if the parameter has getMonth
property.
null
then value.constructor.name
throws an exception.
arrow function
const isValidDate = (value: any) => value instanceof Date && !isNaN(value);
Function:
function isValidDate(d) {
return d instanceof Date && !isNaN(d);
}
You could check if a function specific to the Date object exists:
function getFormatedDate(date) {
if (date.getMonth) {
var month = date.getMonth();
}
}
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'
This function will return true
if it's Date or false
otherwise:
function isDate(myDate) {
return myDate.constructor.toString().indexOf("Date") > -1;
}
isDate(new (function AnythingButNotDate(){ })())
returns true
Yet another variant:
Date.prototype.isPrototypeOf(myDateObject)
instanceof
.
iWindow.Date.prototype.isPrototypeOf(iWindow.date); // true
iWindow.date instanceof iWindow.Date; // true
with the following approach, you can even check date no to be "Invalid Date"
if(!!date.getDate()){
console.log('date is valid')
}
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)));
Simply use moment
import moment from 'moment';
moment(myvar).isValid(); // return true or false
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();
}
}
We can also validate it by below code
var a = new Date();
a.constructor === Date
/*
true
*/
https://i.stack.imgur.com/Sbktx.png
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 stackoverflow.com/a/44198641/5846045
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.
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"
/>
If you are using Typescript you could check using the Date type:
const formatDate( date: Date ) => {}
Couldn't you just use
function getFormatedDate(date) {
if (date.isValid()) {
var month = date.GetMonth();
}
}
isValid
method
isValid
. Only moment.js has such an API.
isValid
method is not available in date object, hence this throws up an error.
Success story sharing
window
orself
); different frames have their own global objects, and their properties (ie globals) refer to distinct objects:Date
in frame1 is a different function object thanDate
in frame2; the same is true forDate.prototype
, which is the reason for theinstanceof
failure:Date.prototype
from frame1 is not part of the prototype chain ofDate
instances from frame2new Date('something') instanceof Date
returnstrue
in Chrome. That won't work then.