Comment vérifier si un objet est une date?

601

J'ai un bug ennuyeux sur une page Web:

date.GetMonth () n'est pas une fonction

Donc, je suppose que je fais quelque chose de mal. La variable daten'est pas un objet de type Date. Comment puis-je vérifier un type de données en Javascript? J'ai essayé d'ajouter un if (date), mais cela ne fonctionne pas.

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

Donc, si je veux écrire du code défensif et empêcher la mise en forme de la date (qui n'est pas une), comment faire?

Merci!

MISE À JOUR: Je ne veux pas vérifier le format de la date, mais je veux être sûr que le paramètre passé à la méthode getFormatedDate()est de type Date.

Martin
la source
Dans le cas où il devrait également être validé si la date n'est pas un Invalid Date: stackoverflow.com/a/44198641/5846045
Boghyon Hoffmann

Réponses:

1110

Comme alternative à la saisie de canard via

typeof date.getMonth === 'function'

vous pouvez utiliser l' instanceofopérateur, c.-à-d. mais il retournera vrai aussi pour les dates invalides, par exemple new Date('random_string')est également une instance de Date

date instanceof Date

Cela échouera si les objets passent au-delà des limites du cadre.

Une solution consiste à vérifier la classe de l'objet via

Object.prototype.toString.call(date) === '[object Date]'
Christoph
la source
29
Par intérêt, connaissez-vous la raison de cet échec lors du franchissement des limites de trame?
Simon Lieschke
85
@Simon: les globaux JS sont locaux à l'objet global actuel (aka windowou self); différents cadres ont leurs propres objets globaux et leurs propriétés (c.-à-d. globaux) se réfèrent à des objets distincts: Datedans le cadre 1 est un objet fonction différent de Datedans le cadre 2; il en va de même pour Date.prototype, ce qui est la raison de l' instanceoféchec: Date.prototypefrom frame1 ne fait pas partie du prototype de la chaîne d' Dateinstances de frame2
Christoph
9
Christoph, qu'est-ce que tu appelles "frame"? IFRAME, chaque trame dans FRAMESET ou autre chose (je veux dire spécifique à JS, pas la chose HTML)?
Paul
12
new Date('something') instanceof Daterevient truedans Chrome. Cela ne fonctionnera pas alors.
krillgar
12
La détection d'un objet de type Date (par opposition à un objet simple ou une chaîne) et la validation d'un objet que vous attendez à être une date sont deux tâches différentes. Il existe un certain nombre de situations où l'entrée de votre fonction peut être l'un d'un certain nombre de types de données différents. Dans mon cas, je peux avoir confiance que tout objet Date que je reçois est valide (il ne vient pas directement d'un client) Si la validation est un problème, voici un article avec un certain nombre d'options. stackoverflow.com/questions/1353684/…
Michael Blackburn
125

Vous pouvez utiliser le code suivant:

(myvar instanceof Date) // returns true or false
SF_dev
la source
6
Pourquoi n'est-ce pas la réponse acceptée ou la plus appréciée? Le simple fait de vérifier si la date possède une propriété .getMonth peut déclencher un faux positif.
doremi
24
instanceof peut déclencher de faux négatifs, voir le commentaire de Christoph à sa propre réponse.
Marco Mariani
2
@doremi Voici une démo de instanceofdéclenchement de faux négatifs: jsbin.com/vufufoq/edit?html,js,console
Boghyon Hoffmann
69

Afin de vérifier si la valeur est un type valide de l'objet date JS standard, vous pouvez utiliser ce prédicat:

function isValidDate(date) {
  return date && Object.prototype.toString.call(date) === "[object Date]" && !isNaN(date);
}
  1. datevérifie si le paramètre n'a pas été une valeur falsy ( undefined, null, 0, "", etc ..)
  2. Object.prototype.toString.call(date)renvoie une représentation sous forme de chaîne native du type d'objet donné - Dans notre cas "[object Date]". Parce que date.toString()remplace sa méthode parente , nous devons .callou .applyla méthode à partir de Object.prototypelaquelle ..
  3. !isNaN(date)vérifie enfin si la valeur n'était pas un Invalid Date.
Boghyon Hoffmann
la source
1
Wow isNaNpeut être utilisé pour vérifier a Date. C'est un certain niveau d'inanité de PHP.
Nick
@Nick a date est un nombre.
Josiah
@Josiah Oui, bien sûr, enlever tout contexte , il y a un horodatage: typeof Date.now() === "number", mais: typeof new Date() === "object". Plus réaliste, cependant, une date est un temps et un lieu dans l'espace.
Nick
39

La fonction n'est getMonth()pas GetMonth().

Quoi qu'il en soit, vous pouvez vérifier si l'objet a une propriété getMonth en procédant ainsi. Cela ne signifie pas nécessairement que l'objet est une date, juste n'importe quel objet qui a une propriété getMonth.

if (date.getMonth) {
    var month = date.getMonth();
}
Chetan Sastry
la source
3
Vérifiez si elle est appelable:if (date.getMonth && typeof date.getMonth === "function") {...}
Aloso
20

Comme indiqué ci-dessus, il est probablement plus facile de vérifier simplement si la fonction existe avant de l'utiliser. Si vous vous souciez vraiment que ce soit un Date, et pas seulement un objet avec une getMonth()fonction, essayez ceci:

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

Cela créera un clone de la valeur s'il s'agit d'un Date, ou créera une date non valide. Vous pouvez ensuite vérifier si la valeur de la nouvelle date n'est pas valide ou non.

bdukes
la source
1
Cela a fonctionné pour moi, merci. Cependant, si vous passez un seul chiffre tel que 0 ou 1, il traite cela comme une date valide ... des pensées?
Ricardo Sanchez
C'est vrai, @RicardoSanchez. Vous voudrez probablement utiliser la réponse acceptée ( Object.prototype.toString.call(value) === '[object Date]') si c'est possible, vous obtiendrez des chiffres. La méthode de cette réponse vous indique vraiment si le valueest convertible en a Date.
bdukes
18

Pour tous les types, j'ai préparé une fonction prototype d'objet. Cela peut vous être utile

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;
}

Vous pouvez maintenant vérifier n'importe quel type comme celui-ci:

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

[ Edit mars 2013 ] basé sur la progression des connaissances, c'est une meilleure méthode:

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
la source
10

UnderscoreJS et Lodash ont une fonction appelée .isDate()qui semble être exactement ce dont vous avez besoin. Cela vaut la peine de regarder leurs implémentations respectives: Lodash isDate , UnderscoreJs

avalanche1
la source
8

La meilleure façon que j'ai trouvée est:

!isNaN(Date.parse("some date test"))
//
!isNaN(Date.parse("22/05/2001"))  // true
!isNaN(Date.parse("blabla"))  // false
jspassov
la source
Ça ne marche pas. Votre vraie ligne est en fait fausse et la question est de vérifier si un objet est un objet de date ...
Clint
1
La réponse @jspassov est plus précise avec si une chaîne est une date ou non. Que je cherchais. Merci!!
Anant
C'est la meilleure réponse pour vérifier simplement si une chaîne est une date ou non
James Gentes
4

Au lieu de toutes les solutions de contournement, vous pouvez utiliser les éléments suivants:

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

J'ai trouvé ce hack meilleur!

itsHarshad
la source
3

Vous pouvez vérifier si une fonction spécifique à l'objet Date existe:

function getFormatedDate(date) {
    if (date.getMonth) {
        var month = date.getMonth();
    }
}
Powerlord
la source
2

Vous pouvez également utiliser un formulaire court

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

ou quelque chose comme ça:

(toString.call(date)) == 'Date'
pavlo
la source
2

J'utilise une méthode beaucoup plus simple, mais je ne sais pas si cela est uniquement disponible dans ES6 ou non.

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"

Cependant, cela ne fonctionnera pas sur null ou indéfini car ils n'ont pas de constructeur.

mjwrazor
la source
Tout objet fait sur mesure avec le nom de constructeur "Date" renvoie "Date"également ce qui est aussi risqué que de simplement vérifier si le paramètre a une getMonthpropriété.
Boghyon Hoffmann
2
@boghyon ressemble à celui qui crée un objet avec le nom du constructeur d'une bibliothèque standard Javascript déjà prédéfinie ne suit pas les meilleures pratiques en premier lieu. Ce serait comme télécharger lodash puis créer votre propre module lodash et attendre que les choses fonctionnent.
mjwrazor
1

Cette fonction retournera truesi c'est Date ou falseautrement:

function isDate(myDate) {
    return myDate.constructor.toString().indexOf("Date") > -1;
} 
Jahid
la source
1
isDate(new (function AnythingButNotDate(){ })())retourstrue
Boghyon Hoffmann
1

Encore une autre variante:

Date.prototype.isPrototypeOf(myDateObject)
Vadim
la source
Agréable et court! Mais malheureusement, il a le même problème queinstanceof .
Boghyon Hoffmann
@BoghyonHoffmann en cas d'iFrame, cela pourrait ressembler à: iWindow.Date.prototype.isPrototypeOf(iWindow.date); // true iWindow.date instanceof iWindow.Date; // true
Vadim
1

Une approche utilisant un try / catch

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

console.log(getFormatedDate());
console.log(getFormatedDate('AAAA'));
console.log(getFormatedDate(new Date('AAAA')));
console.log(getFormatedDate(new Date(2018, 2, 10)));

codeKonami
la source
0

En fait, la date sera de type Object. Mais vous pouvez vérifier si l'objet a une getMonthméthode et s'il est appelable.

function getFormatedDate(date) {
    if (date && date.getMonth && date.getMonth.call) {
       var month = date.getMonth();
    }
}
vartec
la source
2
La réponse de Christoph est plus précise. Avoir une propriété 'call' ne signifie pas nécessairement que c'est une fonction!
Chetan Sastry
-1

Nous pouvons également le valider par le code ci-dessous

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

entrez la description de l'image ici

Arun
la source
Le constructeur de l' function Date() {/*...*/}est aussi Date. C'est-à-dire que la simple comparaison de la fonction constructeur est trop sujette aux erreurs, ce qui entraîne souvent de faux positifs. Contourner le type d'objet défini par l'utilisateur avec stackoverflow.com/a/44198641/5846045
Boghyon Hoffmann
-1

Inspirée par cette réponse , cette solution fonctionne dans mon cas (j'avais besoin de vérifier si la valeur reçue de l'API est une date ou non):

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

De cette façon, s'il s'agit d'une chaîne aléatoire provenant d'un client ou de tout autre objet, vous pouvez savoir s'il s'agit d'un objet de type Date.

Mohammad Ganji
la source
-2

Ne pourriez-vous pas simplement utiliser

function getFormatedDate(date) {
    if (date.isValid()) {
       var month = date.GetMonth();
    }
}
Grincheux
la source
1
Non, seul l'objet date a la isValidméthode
nikk wong
2
@grumpy @nikkwong Non et non. L'objet de date standard n'a pas isValid. Seul moment.js possède une telle API.
Boghyon Hoffmann