Wie überprüfe ich, ob ein Objekt ein Datum ist?

601

Ich habe einen nervigen Fehler auf einer Webseite:

date.GetMonth () ist keine Funktion

Also nehme ich an, dass ich etwas falsch mache. Die Variable dateist kein Objekt vom Typ Date. Wie kann ich in Javascript nach einem Datentyp suchen? Ich habe versucht, ein hinzuzufügen if (date), aber es funktioniert nicht.

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

Wie mache ich das, wenn ich defensiven Code schreiben und verhindern möchte, dass das Datum (welches nicht eines ist) formatiert wird?

Vielen Dank!

UPDATE: Ich möchte das Format des Datums nicht überprüfen, aber ich möchte sicherstellen, dass der an die Methode übergebene Parameter getFormatedDate()vom Typ ist Date.

Martin
quelle
Für den Fall, dass auch überprüft werden sollte, ob das Datum kein Invalid Date: stackoverflow.com/a/44198641/5846045
Boghyon Hoffmann

Antworten:

1109

Als Alternative zum Ententippen über

typeof date.getMonth === 'function'

Sie können den instanceofOperator verwenden, dh er gibt auch für ungültige Daten true zurück, z. B. new Date('random_string')ist auch eine Instanz von Date

date instanceof Date

Dies schlägt fehl, wenn Objekte über Rahmengrenzen hinweg übergeben werden.

Eine Problemumgehung besteht darin, die Klasse des Objekts über zu überprüfen

Object.prototype.toString.call(date) === '[object Date]'
Christoph
quelle
28
Kennen Sie aus Interesse den Grund für dieses Versagen beim Überschreiten von Rahmengrenzen?
Simon Lieschke
85
@ Simon: JS-Globals sind lokal für das aktuelle globale Objekt (auch bekannt als windowoder self). Verschiedene Frames haben ihre eigenen globalen Objekte, und ihre Eigenschaften (dh Globals) beziehen sich auf unterschiedliche Objekte: DateIn Frame1 ist ein anderes Funktionsobjekt als Datein Frame2; das gleiche gilt für Date.prototype, was der Grund für den instanceofFehler ist: Date.prototypevon Frame1 ist nicht Teil der Prototypkette von DateInstanzen von Frame2
Christoph
9
Christoph, wie nennt man "Rahmen"? IFRAME, jeder Frame in FRAMESET oder etwas anderes (ich meine JS-spezifisch, nicht das HTML-Ding)?
Paul
12
new Date('something') instanceof Datekehrt truein Chrome zurück. Das wird dann nicht funktionieren.
Krillgar
12
Das Erkennen eines Objekts vom Typ Datum (im Gegensatz zu einem einfachen Objekt oder einer Zeichenfolge) und das Überprüfen eines Objekts, von dem Sie erwarten, dass es ein Datum ist, sind zwei verschiedene Aufgaben. Es gibt eine Reihe von Situationen, in denen die Eingabe für Ihre Funktion einer von mehreren verschiedenen Datentypen sein kann. In meinem Fall kann ich darauf vertrauen, dass jedes Datumsobjekt, das ich erhalte, gültig ist (es kommt nicht direkt von einem Client). Wenn die Validierung ein Problem darstellt, finden Sie hier einen Beitrag mit einer Reihe von Optionen. stackoverflow.com/questions/1353684/…
Michael Blackburn
125

Sie können den folgenden Code verwenden:

(myvar instanceof Date) // returns true or false
SF_dev
quelle
6
Warum ist dies nicht die akzeptierte oder positivere Antwort? Das einfache Überprüfen, ob das Datum eine .getMonth-Eigenschaft hat, kann ein falsches Positiv auslösen.
Doremi
24
Instanz kann falsche Negative auslösen, siehe Christophs Kommentar zu seiner eigenen Antwort.
Marco Mariani
2
@doremi Hier ist eine Demo zum instanceofAuslösen von falschem Negativ: jsbin.com/vufufoq/edit?html,js,console
Boghyon Hoffmann
68

Um zu überprüfen, ob der Wert ein gültiger Typ des Standard-JS-Datumsobjekts ist, können Sie dieses Prädikat verwenden:

function isValidDate(date) {
  return date && Object.prototype.toString.call(date) === "[object Date]" && !isNaN(date);
}
  1. dateüberprüft , ob der Parameter kein war falsy Wert ( undefined, null, 0, "", etc ..)
  2. Object.prototype.toString.call(date)Gibt eine native Zeichenfolgendarstellung des angegebenen Objekttyps zurück. In unserem Fall "[object Date]". Da date.toString()die übergeordnete Methode überschrieben wird , müssen wir .calloder .applydie Methode Object.prototypedirekt von welcher ..
  3. !isNaN(date)prüft schließlich, ob der Wert nicht ein war Invalid Date.
Boghyon Hoffmann
quelle
1
Wow isNaNkann verwendet werden, um a zu überprüfen Date. Das ist ein PHP-Level an Irrsinn.
Nick
@Nick ein Datum ist allerdings eine Zahl.
Josiah
@ Josiah Nun, sicher, wenn man den gesamten Kontext entfernt, gibt es dort einen Zeitstempel : typeof Date.now() === "number", aber : typeof new Date() === "object". Realistischer ist ein Datum jedoch eine Zeit und ein Ort im Raum.
Nick
39

Die Funktion ist getMonth()nicht GetMonth().

Auf diese Weise können Sie überprüfen, ob das Objekt eine getMonth-Eigenschaft hat. Dies bedeutet nicht unbedingt, dass das Objekt ein Datum ist, sondern nur ein Objekt mit einer getMonth-Eigenschaft.

if (date.getMonth) {
    var month = date.getMonth();
}
Chetan Sastry
quelle
3
Überprüfen Sie, ob es aufrufbar ist:if (date.getMonth && typeof date.getMonth === "function") {...}
Aloso
20

Wie oben angegeben, ist es wahrscheinlich am einfachsten, vor der Verwendung zu überprüfen, ob die Funktion vorhanden ist. Wenn es Ihnen wirklich wichtig ist, dass es sich um Dateein Objekt handelt und nicht nur um ein Objekt mit einer getMonth()Funktion, versuchen Sie Folgendes:

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

Dadurch wird entweder ein Klon des Werts erstellt, falls es sich um einen handelt Date, oder es wird ein ungültiges Datum erstellt. Sie können dann überprüfen, ob der Wert des neuen Datums ungültig ist oder nicht.

bdukes
quelle
1
Das hat bei mir funktioniert, danke. Wenn Sie jedoch eine einzelne Ziffer wie 0 oder 1 übergeben, wird dies als gültiges Datum behandelt ... irgendwelche Gedanken?
Ricardo Sanchez
Das stimmt, @RicardoSanchez. Sie möchten wahrscheinlich die akzeptierte Antwort ( Object.prototype.toString.call(value) === '[object Date]') verwenden, wenn es möglich ist, dass Sie Zahlen erhalten. Die Methode in dieser Antwort sagt Ihnen wirklich, ob das valuein a konvertierbar ist Date.
Bdukes
18

Für alle Typen habe ich eine Object-Prototyp-Funktion erstellt. Es kann für Sie von Nutzen sein

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

Jetzt können Sie jeden Typ wie folgt überprüfen :

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

[ März 2013 bearbeiten ] Basierend auf fortschreitenden Erkenntnissen ist dies eine bessere Methode:

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
quelle
8

Der beste Weg, den ich gefunden habe, ist:

!isNaN(Date.parse("some date test"))
//
!isNaN(Date.parse("22/05/2001"))  // true
!isNaN(Date.parse("blabla"))  // false
jspassov
quelle
Das funktioniert nicht. Ihre wahre Linie ist tatsächlich falsch und die Frage ist zu überprüfen, ob ein Objekt ein Datumsobjekt ist ...
Clint
1
Die Antwort von @jspassov ist genauer, wenn eine Zeichenfolge ein Datum ist oder nicht. Das habe ich gesucht. Vielen Dank!!
Anant
Dies ist die beste Antwort, um einfach zu überprüfen, ob eine Zeichenfolge ein Datum ist oder nicht
James Gentes
3

Sie können überprüfen, ob eine für das Date-Objekt spezifische Funktion vorhanden ist:

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

Anstelle aller Problemumgehungen können Sie Folgendes verwenden:

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

Ich fand diesen Hack besser!

itsHarshad
quelle
2

Sie können auch eine Kurzform verwenden

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

oder so ähnlich:

(toString.call(date)) == 'Date'
Pavlo
quelle
2

Ich habe einen viel einfacheren Weg verwendet, bin mir aber nicht sicher, ob dies nur in ES6 verfügbar ist oder nicht.

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"

Dies funktioniert jedoch nicht mit null oder undefiniert, da sie keinen Konstruktor haben.

mjwrazor
quelle
Jedes benutzerdefinierte Objekt mit dem Konstruktornamen "Date" wird ebenfalls zurückgegeben. Dies "Date"ist genauso riskant wie die Überprüfung, ob der Parameter eine getMonthEigenschaft hat.
Boghyon Hoffmann
2
@boghyon klingt so, als ob derjenige, der ein Objekt mit dem Konstruktornamen einer bereits vordefinierten Javascript-Standardbibliothek erstellt, in erster Linie nicht den Best Practices folgt. Das wäre so, als würde man lodash herunterladen, dann ein eigenes lodash-Modul erstellen und erwarten, dass die Dinge funktionieren.
mjwrazor
1

Diese Funktion wird zurückgegeben, truewenn es sich um ein Datum oder eine falseandere handelt:

function isDate(myDate) {
    return myDate.constructor.toString().indexOf("Date") > -1;
} 
Jahid
quelle
1
isDate(new (function AnythingButNotDate(){ })())kehrt zurücktrue
Boghyon Hoffmann
1

Noch eine Variante:

Date.prototype.isPrototypeOf(myDateObject)
Vadim
quelle
Schön kurz! Aber leider hat es das gleiche Problem wieinstanceof .
Boghyon Hoffmann
@ BoghyonHoffmann im Falle von iFrame kann es so aussehen: iWindow.Date.prototype.isPrototypeOf(iWindow.date); // true iWindow.date instanceof iWindow.Date; // true
Vadim
1

Ein Ansatz mit einem Versuch / Fang

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
quelle
0

Tatsächlich ist das Datum vom Typ Object. Sie können jedoch überprüfen, ob das Objekt über eine getMonthMethode verfügt und ob es aufrufbar ist.

function getFormatedDate(date) {
    if (date && date.getMonth && date.getMonth.call) {
       var month = date.getMonth();
    }
}
vartec
quelle
2
Christophs Antwort ist genauer. Eine 'call'-Eigenschaft bedeutet nicht unbedingt, dass es sich um eine Funktion handelt!
Chetan Sastry
-1

Wir können es auch anhand des folgenden Codes validieren

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

Geben Sie hier die Bildbeschreibung ein

Arun
quelle
Der Konstruktor von function Date() {/*...*/}ist auch Date. Das einfache Vergleichen der Konstruktorfunktion ist zu fehleranfällig, was häufig zu falsch positiven Ergebnissen führt. Benutzerdefinierten Objekttyp mit stackoverflow.com/a/44198641/5846045 umgehen
Boghyon Hoffmann
-1

Inspiriert von dieser Antwort funktioniert diese Lösung in meinem Fall (ich musste überprüfen, ob der von der API empfangene Wert ein Datum ist oder nicht):

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

Auf diese Weise können Sie herausfinden, ob es sich um ein datumsähnliches Objekt handelt, wenn es sich um eine zufällige Zeichenfolge handelt, die von einem Client oder einem anderen Objekt stammt.

Mohammad Ganji
quelle
-2

Könnten Sie nicht einfach verwenden

function getFormatedDate(date) {
    if (date.isValid()) {
       var month = date.GetMonth();
    }
}
Mürrisch
quelle
1
Nein, nur das isValid
Datumsobjekt
2
@grumpy @nikkwong Nein und nein. Das Standard-Datumsobjekt hat nicht isValid. Nur moment.js hat eine solche API.
Boghyon Hoffmann