Como verificar se um objeto é uma data?

601

Eu tenho um bug irritante em uma página da web:

date.GetMonth () não é uma função

Então, suponho que estou fazendo algo errado. A variável datenão é um objecto do tipo Date. Como posso verificar um tipo de dados em Javascript? Tentei adicionar um if (date), mas não funciona.

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

Então, se eu quiser escrever um código defensivo e impedir que a data (que não é uma) seja formatada, como faço isso?

Obrigado!

UPDATE: Não quero verificar o formato da data, mas quero ter certeza de que o parâmetro passado para o método getFormatedDate()é do tipo Date.

Martin
fonte
Caso também deva ser validado se a data não é uma Invalid Date: stackoverflow.com/a/44198641/5846045
Boghyon Hoffmann

Respostas:

1110

Como alternativa à digitação por pato via

typeof date.getMonth === 'function'

você pode usar o instanceofoperador, ou seja, mas também retornará true para datas inválidas, por exemplo, new Date('random_string')também é instância de Date

date instanceof Date

Isso falhará se os objetos forem passados ​​através dos limites do quadro.

Uma solução alternativa para isso é verificar a classe do objeto via

Object.prototype.toString.call(date) === '[object Date]'
Christoph
fonte
29
Por interesse, você sabe o motivo dessa falha ao atravessar os limites do quadro?
Simon Lieschke
85
@ Simon: JS globais são locais para o objeto global atual (aka windowou self); quadros diferentes têm seus próprios objetos globais e suas propriedades (isto é, globais) se referem a objetos distintos: Dateno quadro1 é um objeto de função diferente do Datequadro2; o mesmo é verdadeiro para Date.prototype, que é a razão para o instanceoffracasso: Date.prototypea partir frame1 não faz parte da cadeia de protótipos de Datecasos de frame2
Christoph
9
Christoph, como você chama "moldura"? IFRAME, cada quadro no FRAMESET ou qualquer outra coisa (quero dizer específico de JS, não o HTML)?
Paul
12
new Date('something') instanceof Dateretorna trueno Chrome. Isso não vai funcionar então.
krillgar
12
Detectar um objeto do tipo Data (em oposição a um Objeto ou sequência simples) e validar um objeto que você espera que seja uma Data são duas tarefas diferentes. Existem várias situações em que a entrada para sua função pode ser um de vários tipos de dados diferentes. No meu caso, posso confiar que qualquer objeto Date que recebo é válido (não vem diretamente de um cliente). Se validar é uma preocupação, aqui está uma postagem com várias opções. stackoverflow.com/questions/1353684/…
Michael Blackburn
125

Você pode usar o seguinte código:

(myvar instanceof Date) // returns true or false
SF_dev
fonte
6
Por que essa não é a resposta aceita ou mais votada? Simplesmente verificar se date possui uma propriedade .getMonth pode disparar um falso positivo.
precisa
24
instanceof pode desencadear falsos negativos, veja o comentário de Christoph para sua própria resposta.
Marco Mariani
2
@doremi Aqui está uma demonstração de instanceofdisparo falso negativo: jsbin.com/vufufoq/edit?html,js,console
Boghyon Hoffmann
69

Para verificar se o valor é um tipo válido do objeto JS-date padrão, você pode usar este predicado:

function isValidDate(date) {
  return date && Object.prototype.toString.call(date) === "[object Date]" && !isNaN(date);
}
  1. dateverifica se o parâmetro não foi um valor Falsas ( undefined, null, 0, "", etc ..)
  2. Object.prototype.toString.call(date)retorna uma representação de string nativa do tipo de objeto especificado - no nosso caso "[object Date]". Como date.toString()substitui seu método pai , precisamos .callou .applyo método Object.prototypediretamente do qual ..
  3. !isNaN(date)finalmente verifica se o valor não era um Invalid Date.
Boghyon Hoffmann
fonte
1
Uau isNaNpode ser usado para verificar a Date. Isso é algum nível de inanidade do PHP.
Nick
@Nick uma data é um número embora.
Josiah
@Josiah Bem, com certeza, a remoção de todo o contexto há um timestamp lá: typeof Date.now() === "number", mas: typeof new Date() === "object". Mais realisticamente, porém, uma data é uma hora e um local no espaço.
Nick
39

A função é getMonth()não GetMonth().

De qualquer forma, você pode verificar se o objeto tem uma propriedade getMonth fazendo isso. Isso não significa necessariamente que o objeto é uma Data, apenas qualquer objeto que tenha uma propriedade getMonth.

if (date.getMonth) {
    var month = date.getMonth();
}
Chetan Sastry
fonte
3
Verifique se é possível if (date.getMonth && typeof date.getMonth === "function") {...}
chamar
20

Como indicado acima, provavelmente é mais fácil apenas verificar se a função existe antes de usá-la. Se você realmente se importa que seja um Date, e não apenas um objeto com uma getMonth()função, tente o seguinte:

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

Isso criará um clone do valor, se for um Date, ou criará uma data inválida. Você pode então verificar se o valor da nova data é inválido ou não.

bdukes
fonte
1
Isso funcionou para mim, obrigado. No entanto, se você passar um único dígito como 0 ou 1, trata-o como uma Data válida ... alguma opinião?
Ricardo Sanchez
É isso mesmo, RicardoSanchez. Você provavelmente deseja usar a resposta aceita ( Object.prototype.toString.call(value) === '[object Date]') se for possível obter números. O método nesta resposta realmente informa se o valueé conversível em a Date.
bdukes
18

Para todos os tipos, criei uma função de protótipo de objeto. Pode ser útil para você

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

Agora você pode verificar qualquer tipo como este:

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

[ Editar março de 2013 ] com base na percepção progressiva, este é um método melhor:

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
fonte
10

O UnderscoreJS e o Lodash têm uma função chamada .isDate()que parece ser exatamente o que você precisa. Vale a pena olhar para as respectivas implementações: Lodash isDate , UnderscoreJs

avalanche1
fonte
8

A melhor maneira que encontrei é:

!isNaN(Date.parse("some date test"))
//
!isNaN(Date.parse("22/05/2001"))  // true
!isNaN(Date.parse("blabla"))  // false
jspassov
fonte
Isso não funciona. Sua verdadeira linha realmente é falsa ea questão é sobre como verificar se um objeto é um objeto de data ...
Clint
1
A resposta @jspassov é mais precisa se uma string é uma data ou não. Que eu estava procurando. Obrigado!!
Anant
Esta é a melhor resposta para simplesmente verificar se uma string é uma data ou não
James Gentes
3

Você pode verificar se existe uma função específica para o objeto Date:

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

Em vez de todas as soluções alternativas, você pode usar o seguinte:

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

Eu achei esse hack melhor!

itsHarshad
fonte
2

Além disso, você pode usar o formulário curto

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

ou algo parecido com isto:

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

Estou usando uma maneira muito mais simples, mas não tenho certeza se isso está disponível apenas no ES6 ou não.

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"

No entanto, isso não funcionará em nulo ou indefinido, pois eles não têm construtor.

mjwrazor
fonte
Qualquer objeto personalizado com o nome do construtor "Data" "Date"também retorna, o que é tão arriscado quanto apenas verificar se o parâmetro tem getMonthpropriedade.
Boghyon Hoffmann
2
O @boghyon parece que quem cria um objeto com o nome do construtor de uma biblioteca padrão Javascript já predefinida não segue as práticas recomendadas. Isso seria como baixar o lodash e criar seu próprio módulo e esperar que as coisas funcionassem.
mjwrazor
1

Esta função retornará truese for Data ou falsenão:

function isDate(myDate) {
    return myDate.constructor.toString().indexOf("Date") > -1;
} 
Jahid
fonte
1
isDate(new (function AnythingButNotDate(){ })())retornatrue
Boghyon Hoffmann 12/04
1

Ainda outra variante:

Date.prototype.isPrototypeOf(myDateObject)
Vadim
fonte
Bom e curto! Mas, infelizmente, tem o mesmo problemainstanceof .
Boghyon Hoffmann
@BoghyonHoffmann em caso de iFrame pode olhar como: iWindow.Date.prototype.isPrototypeOf(iWindow.date); // true iWindow.date instanceof iWindow.Date; // true
Vadim
1

Uma abordagem usando uma tentativa / captura

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

Na verdade, a data será do tipo Object. Mas você pode verificar se o objeto tem getMonthmétodo e se é possível chamar.

function getFormatedDate(date) {
    if (date && date.getMonth && date.getMonth.call) {
       var month = date.getMonth();
    }
}
vartec
fonte
2
A resposta de Christoph é mais precisa. Ter uma propriedade 'call' não significa necessariamente que é uma função!
Chetan Sastry
-1

Também podemos validá-lo pelo código abaixo

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

insira a descrição da imagem aqui

Uma corrida
fonte
O construtor de function Date() {/*...*/}é também Date. Ou seja, simplesmente comparar a função construtora é muito propenso a erros, o que geralmente resulta em falsos positivos. Ignore o tipo de objeto definido pelo usuário com stackoverflow.com/a/44198641/5846045
Boghyon Hoffmann em
-1

Inspirada nesta resposta , esta solução funciona no meu caso (eu precisava verificar se o valor recebido da API é uma data ou não):

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

Dessa forma, se houver alguma sequência aleatória proveniente de um cliente ou qualquer outro objeto, você poderá descobrir se é um objeto semelhante a uma Data.

Mohammad Ganji
fonte
-2

Você não poderia simplesmente usar

function getFormatedDate(date) {
    if (date.isValid()) {
       var month = date.GetMonth();
    }
}
Mal humorado
fonte
1
Não, apenas o objeto de data tem o isValidmétodo
Nikk wong
2
@grumpy @nikkwong Não e não. O objeto de data padrão não possui isValid. Somente o moment.js possui essa API.
Boghyon Hoffmann