Come verificare se un oggetto è una data?


601

Ho un fastidioso bug in una pagina web:

date.GetMonth () non è una funzione

Quindi, suppongo che sto facendo qualcosa di sbagliato. La variabile datenon è un oggetto di tipo Date. Come posso verificare un tipo di dati in Javascript? Ho provato ad aggiungere un if (date), ma non funziona.

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

Quindi, se voglio scrivere un codice difensivo e impedire la formattazione della data (che non è una), come posso farlo?

Grazie!

AGGIORNAMENTO: Non voglio controllare il formato della data, ma voglio essere sicuro che il parametro passato al metodo getFormatedDate()sia di tipo Date.


Nel caso in cui si dovrebbe anche convalidato se la data di non è una Invalid Date: stackoverflow.com/a/44198641/5846045
Boghyon Hoffmann

Risposte:


1110

In alternativa all'anatra digitando via

typeof date.getMonth === 'function'

puoi usare l' instanceofoperatore, ad es. Ma tornerà vero anche per date non valide, ad es. new Date('random_string')è anche un'istanza di Date

date instanceof Date

Ciò fallirà se gli oggetti passano attraverso i confini del frame.

Una soluzione per questo è controllare la classe dell'oggetto tramite

Object.prototype.toString.call(date) === '[object Date]'

29
Per interesse, conosci la ragione di questo errore quando attraversi i confini del frame?
Simon Lieschke,

85
@Simon: i globi JS sono locali per l'oggetto globale corrente (aka windowo self); frame diversi hanno i loro oggetti globali e le loro proprietà (cioè globali) si riferiscono a oggetti distinti: Datein frame1 è un oggetto funzione diverso rispetto Datea frame2; lo stesso vale per Date.prototype, che è la ragione instanceofdell'errore: Date.prototypeda frame1 non fa parte della catena prototipo di Dateistanze da frame2
Christoph

9
Christoph, come si chiama "frame"? IFRAME, ogni frame in FRAMESET o qualcos'altro (intendo JS specifico, non la cosa HTML)?
Paul,

12
new Date('something') instanceof Dateritorna truein Chrome. Allora non funzionerà.
Krillgar,

12
Rilevare un oggetto di tipo Data (anziché un oggetto semplice o una stringa) e convalidare un oggetto che si prevede sia una data sono due attività diverse. Esistono diverse situazioni in cui l'input per la tua funzione potrebbe essere uno dei vari tipi di dati. Nel mio caso, posso fidarmi che qualsiasi oggetto Date che ottengo è valido (non proviene direttamente da un client) Se la convalida è un problema, ecco un post con una serie di opzioni. stackoverflow.com/questions/1353684/…
Michael Blackburn,

125

Puoi usare il seguente codice:

(myvar instanceof Date) // returns true or false

6
Perché questa non è la risposta accettata o più votata? Il semplice controllo se date ha una proprietà .getMonth potrebbe innescare un falso positivo.
Doremi,

24
instanceof può innescare falsi negativi, vedi il commento di Christoph alla sua stessa risposta.
Marco Mariani,

2
@doremi Ecco una demo per instanceofinnescare falsi negativi: jsbin.com/vufufoq/edit?html,js,console
Boghyon Hoffmann

69

Per verificare se il valore è un tipo valido dell'oggetto standard JS-date, è possibile utilizzare questo predicato:

function isValidDate(date) {
  return date && Object.prototype.toString.call(date) === "[object Date]" && !isNaN(date);
}
  1. datecontrolla se il parametro non è stato un valore di falsy ( undefined, null, 0, "", ecc ..)
  2. Object.prototype.toString.call(date)restituisce una rappresentazione di stringa nativa del tipo di oggetto specificato - Nel nostro caso "[object Date]". Perché date.toString()sovrascrive il suo metodo genitore , dobbiamo .callo .applyil metodo Object.prototypedirettamente dal quale
  3. !isNaN(date)controlla infine se il valore non era un Invalid Date.

1
Wow isNaNpuò essere usato per controllare a Date. Questo è un certo livello di pazzia di PHP.
Nick,

@Nick una data è un numero però.
Giosia il

@Josiah Beh, certo, la rimozione di tutto il contesto c'è un timestamp lì: typeof Date.now() === "number"ma: typeof new Date() === "object". Più realisticamente, tuttavia, una data è un tempo e un luogo nello spazio.
Nick,

39

La funzione è getMonth()no GetMonth().

Ad ogni modo, puoi verificare se l'oggetto ha una proprietà getMonth in questo modo. Non significa necessariamente che l'oggetto sia una Data, ma qualsiasi oggetto che abbia una proprietà getMonth.

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

3
Verifica se è richiamabile:if (date.getMonth && typeof date.getMonth === "function") {...}
Aloso

20

Come indicato sopra, è probabilmente più semplice verificare se la funzione esiste prima di usarla. Se ti interessa davvero che sia un Date, e non solo un oggetto con una getMonth()funzione, prova questo:

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

Questo creerà un clone del valore se è un Date, o creerà una data non valida. È quindi possibile verificare se il valore della nuova data non è valido o meno.


1
Questo ha funzionato per me, grazie. Tuttavia, se passi una singola cifra come 0 o 1, la considera come una Data valida ... qualche pensiero?
Ricardo Sanchez,

Esatto, @RicardoSanchez. Probabilmente vuoi usare la risposta accettata ( Object.prototype.toString.call(value) === '[object Date]') se è possibile otterrai numeri. Il metodo in questa risposta ti dice davvero se valueè convertibile in a Date.
bdukes il

18

Per tutti i tipi ho elaborato una funzione prototipo Object. Potrebbe esserti 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;
}

Ora puoi controllare qualsiasi tipo come questo:

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

[ Modifica marzo 2013 ] sulla base delle informazioni avanzate, questo è un metodo migliore:

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

Il modo migliore che ho trovato è:

!isNaN(Date.parse("some date test"))
//
!isNaN(Date.parse("22/05/2001"))  // true
!isNaN(Date.parse("blabla"))  // false

Questo non funziona La tua vera linea è in realtà falsa e la domanda riguarda il controllo se un oggetto è un oggetto data ...
Clint

1
La risposta di @jspassov è più precisa se una stringa è una data o meno. Quello che stavo cercando. Grazie!!
Anant,

Questa è la risposta migliore per controllare semplicemente se una stringa è una data o meno
James Gentes,

4

Invece di tutte le soluzioni alternative è possibile utilizzare quanto segue:

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

Ho trovato questo trucco migliore!


3

È possibile verificare l'esistenza di una funzione specifica per l'oggetto Date:

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

2

Inoltre puoi usare la forma abbreviata

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

o qualcosa del genere:

(toString.call(date)) == 'Date'

2

Ho usato un modo molto più semplice ma non sono sicuro che questo sia disponibile solo in ES6 o meno.

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"

Tuttavia, questo non funzionerà su null o indefinito poiché non hanno un costruttore.


Restituisce "Date"anche qualsiasi oggetto personalizzato con il nome del costruttore "Date", il che è rischioso come controllare se il parametro ha getMonthproprietà.
Boghyon Hoffmann,

2
@boghyon sembra che chiunque crei un oggetto con il nome del costruttore di una libreria standard Javascript già predefinita non sta seguendo le migliori pratiche in primo luogo. Sarebbe come scaricare lodash, quindi creare il proprio modulo lodash e aspettarsi che le cose funzionino.
mjwrazor,

1

Questa funzione verrà restituita truese è Data o in falsealtro modo:

function isDate(myDate) {
    return myDate.constructor.toString().indexOf("Date") > -1;
} 

1
isDate(new (function AnythingButNotDate(){ })())ritornatrue
Boghyon Hoffmann,

1

Ancora un'altra variante:

Date.prototype.isPrototypeOf(myDateObject)

Bello e breve! Ma sfortunatamente, ha lo stesso problema diinstanceof .
Boghyon Hoffmann,

@BoghyonHoffmann in caso di iFrame potrebbe sembrare: iWindow.Date.prototype.isPrototypeOf(iWindow.date); // true iWindow.date instanceof iWindow.Date; // true
Vadim

1

Un approccio che utilizza un tentativo / cattura

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

In realtà la data sarà di tipo Object. Ma puoi verificare se l'oggetto ha un getMonthmetodo e se è richiamabile.

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

2
La risposta di Christoph è più accurata. Avere una proprietà 'call' non significa necessariamente che sia una funzione!
Chetan Sastry,

-1

Possiamo anche convalidarlo con il seguente codice

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

inserisci qui la descrizione dell'immagine


Il costruttore di function Date() {/*...*/}è anche Date. Vale a dire semplicemente confrontare la funzione di costruzione è troppo soggetto a errori che spesso si traduce in falsi positivi. Bypass tipo di oggetto definito dall'utente con stackoverflow.com/a/44198641/5846045
Boghyon Hoffmann

-1

Ispirata da questa risposta , questa soluzione funziona nel mio caso (avevo bisogno di verificare se il valore ricevuto dall'API è una data o meno):

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

In questo modo, se si tratta di una stringa casuale proveniente da un client o di qualsiasi altro oggetto, è possibile scoprire se si tratta di un oggetto simile a una data.


-2

Non potresti semplicemente usare

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

1
No, solo l'oggetto data ha il isValidmetodo
nikk wong,

2
@grumpy @nikkwong No e no. L'oggetto data standard non ha isValid. Solo moment.js ha una tale API.
Boghyon Hoffmann,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.