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.


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]'

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

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.

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

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.


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


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

Ç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!


3

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

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

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'

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.


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

1
isDate(new (function AnythingButNotDate(){ })())retourstrue
Boghyon Hoffmann

1

Encore une autre variante:

Date.prototype.isPrototypeOf(myDateObject)

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


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

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


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.


-2

Ne pourriez-vous pas simplement utiliser

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

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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.