Jak sprawdzić, czy obiekt jest datą?

601

Mam irytujący błąd na stronie:

date.GetMonth () nie jest funkcją

Przypuszczam więc, że robię coś złego. Zmienna datenie jest obiektem typu Date. Jak mogę sprawdzić typ danych w JavaScript? Próbowałem dodać if (date), ale to nie działa.

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

Jeśli więc chcę napisać kod obronny i uniemożliwić sformatowanie daty (która nie jest jedną), jak to zrobić?

Dzięki!

AKTUALIZACJA: Nie chcę sprawdzać formatu daty, ale chcę mieć pewność, że parametr przekazany do metody getFormatedDate()jest typu Date.

Jaskółka oknówka
źródło
W przypadku, gdy należy również sprawdzić, czy data nie jest Invalid Date: stackoverflow.com/a/44198641/5846045
Boghyon Hoffmann

Odpowiedzi:

1109

Jako alternatywa dla pisania kaczką przez

typeof date.getMonth === 'function'

możesz użyć instanceofoperatora, tzn. Ale zwróci on również prawdę dla niepoprawnych dat, np. new Date('random_string')jest także instancją Date

date instanceof Date

Nie powiedzie się, jeśli obiekty zostaną przekroczone przez granice ramek.

Obejściem tego problemu jest sprawdzenie klasy obiektu za pomocą

Object.prototype.toString.call(date) === '[object Date]'
Christoph
źródło
28
Czy z powodu zainteresowania znasz przyczynę tego niepowodzenia podczas przekraczania granic ramki?
Simon Lieschke
85
@Simon: Globały JS są lokalne dla bieżącego obiektu globalnego (aka windowlub self); różne ramki mają swoje własne obiekty globalne, a ich właściwości (tj. globale) odnoszą się do odrębnych obiektów: Datew frame1 jest innym obiektem funkcji niż Datew frame2; to samo dotyczy Date.prototype, co jest przyczyną instanceofniepowodzenia: Date.prototypez klatki 1 nie jest częścią prototypowego łańcucha Dateinstancji z klatki 2
Christoph
9
Christoph, co nazywasz „ramą”? IFRAME, każda ramka w FRAMESET lub coś innego (mam na myśli specyficzne dla JS, a nie HTML)?
Paul
12
new Date('something') instanceof Datepowraca truew Chrome. To nie zadziała.
krillgar
12
Wykrywanie obiektu typu Data (w przeciwieństwie do zwykłego obiektu lub ciągu) i sprawdzanie poprawności obiektu, który ma być Datą, to dwa różne zadania. Istnieje wiele sytuacji, w których dane wejściowe do funkcji mogą być jednym z wielu różnych typów danych. W moim przypadku mogę ufać, że każdy otrzymany obiekt Date jest prawidłowy (nie pochodzi bezpośrednio od klienta) Jeśli sprawdzanie poprawności stanowi problem, oto post z wieloma opcjami. stackoverflow.com/questions/1353684/…
Michael Blackburn
125

Możesz użyć następującego kodu:

(myvar instanceof Date) // returns true or false
SF_dev
źródło
6
Dlaczego nie jest to zaakceptowana lub bardziej pozytywna odpowiedź? Samo sprawdzenie, czy data ma właściwość .getMonth, może wywołać fałszywy alarm.
doremi,
24
instanceof może wywoływać fałszywe negatywy, patrz komentarz Christopha do jego własnej odpowiedzi.
Marco Mariani,
2
@doremi Oto demonstracja instanceofwyzwalania fałszywego negatywu: jsbin.com/vufufoq/edit?html,js,console
Boghyon Hoffmann
67

Aby sprawdzić, czy wartość jest poprawnym typem standardowego obiektu JS-date, możesz użyć tego predykatu:

function isValidDate(date) {
  return date && Object.prototype.toString.call(date) === "[object Date]" && !isNaN(date);
}
  1. datesprawdza czy parametr nie był wartość falsy ( undefined, null, 0, "", itp ..)
  2. Object.prototype.toString.call(date)zwraca natywną reprezentację ciągu danego typu obiektu - w naszym przypadku "[object Date]". Ponieważ date.toString()przesłania metodę nadrzędną , musimy .calllub .applymetodę, z Object.prototypektórej bezpośrednio…
  3. !isNaN(date)w końcu sprawdza, czy wartość nie była Invalid Date.
Boghyon Hoffmann
źródło
1
Wow isNaNmożna wykorzystać do sprawdzenia Date. To jakiś poziom niepoczytalności PHP.
Nick
@Nata data to jednak liczba.
Josiah
@Josiah Cóż, na pewno, usuwając cały kontekst jest datownik tam: typeof Date.now() === "number", ale: typeof new Date() === "object". Bardziej realistycznie jednak data to czas i miejsce w przestrzeni.
Nick
39

Ta funkcja to getMonth()nie GetMonth().

W każdym razie możesz sprawdzić, czy obiekt ma właściwość getMonth, wykonując tę ​​czynność. Nie musi to oznaczać, że obiekt jest datą, tylko każdy obiekt, który ma właściwość getMonth.

if (date.getMonth) {
    var month = date.getMonth();
}
Chetan Sastry
źródło
3
Sprawdź, czy można to if (date.getMonth && typeof date.getMonth === "function") {...}
wywołać
20

Jak wskazano powyżej, prawdopodobnie najłatwiej jest po prostu sprawdzić, czy funkcja istnieje przed użyciem. Jeśli naprawdę zależy Ci na tym, aby był to obiekt Date, a nie tylko obiekt z getMonth()funkcją, spróbuj tego:

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

Spowoduje to utworzenie klonu wartości, jeśli jest Date, lub utworzenie niepoprawnej daty. Następnie możesz sprawdzić, czy wartość nowej daty jest nieprawidłowa, czy nie.

bdukes
źródło
1
To zadziałało dla mnie, dzięki. Jeśli jednak podasz jedną cyfrę, taką jak 0 lub 1, traktuje to jako prawidłową datę ... jakieś myśli?
Ricardo Sanchez
Zgadza się, @RicardoSanchez. Prawdopodobnie chcesz użyć zaakceptowanej odpowiedzi ( Object.prototype.toString.call(value) === '[object Date]'), jeśli to możliwe, będziesz otrzymywać liczby. Metoda w tej odpowiedzi naprawdę mówi, czy valuemożna ją przekonwertować na Date.
bdukes
18

Dla wszystkich typów przygotowałem funkcję prototypu Object. Może ci się przydać

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

Teraz możesz sprawdzić dowolny typ tego typu:

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

[ Edytuj marzec 2013 ] w oparciu o postęp wglądu jest to lepsza metoda:

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
źródło
8

Najlepszy sposób, jaki znalazłem, to:

!isNaN(Date.parse("some date test"))
//
!isNaN(Date.parse("22/05/2001"))  // true
!isNaN(Date.parse("blabla"))  // false
jspassov
źródło
To nie działa Twoja prawdziwa linia jest w rzeczywistości fałszywa, a pytanie dotyczy sprawdzenia, czy obiekt jest obiektem daty ...
Clint
1
Odpowiedź @jspassov jest dokładniejsza, jeśli ciąg znaków jest datą, czy nie. Tego szukałem. Dzięki!!
Anant
To najlepsza odpowiedź na proste sprawdzenie, czy napis jest datą, czy nie
James Gentes,
3

Możesz sprawdzić, czy istnieje funkcja specyficzna dla obiektu Date:

function getFormatedDate(date) {
    if (date.getMonth) {
        var month = date.getMonth();
    }
}
Władca
źródło
3

Zamiast wszystkich obejść można użyć następujących opcji:

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

Znalazłem ten hack lepiej!

itsHarshad
źródło
2

Możesz także użyć krótkiego formularza

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

lub coś w tym stylu:

(toString.call(date)) == 'Date'
pavlo
źródło
2

Korzystałem z dużo prostszego sposobu, ale nie jestem pewien, czy jest to dostępne tylko w ES6, czy nie.

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"

Nie będzie to jednak działać w przypadku wartości NULL lub niezdefiniowanej, ponieważ nie mają one konstruktora.

mjwrazor
źródło
Zwraca "Date"również dowolny obiekt niestandardowy o nazwie konstruktora „Data”, co jest tak ryzykowne, jak samo sprawdzenie, czy parametr ma getMonthwłaściwość.
Boghyon Hoffmann
2
@boghyon brzmi jak ktoś, kto tworzy obiekt o nazwie konstruktora już zdefiniowanej standardowej biblioteki JavaScript, nie przestrzega przede wszystkim najlepszych praktyk. To byłoby jak pobranie lodash, a następnie utworzenie własnego modułu lodash i oczekiwanie, że wszystko zadziała.
mjwrazor
1

Ta funkcja zwróci, truejeśli jest to data lub w falseinny sposób:

function isDate(myDate) {
    return myDate.constructor.toString().indexOf("Date") > -1;
} 
Jahid
źródło
1
isDate(new (function AnythingButNotDate(){ })())zwrotytrue
Boghyon Hoffmann
1

Jeszcze inny wariant:

Date.prototype.isPrototypeOf(myDateObject)
Vadim
źródło
Miło i krótko! Ale niestety ma ten sam problem coinstanceof .
Boghyon Hoffmann
@BoghyonHoffmann w przypadku iFrame może wyglądać następująco: iWindow.Date.prototype.isPrototypeOf(iWindow.date); // true iWindow.date instanceof iWindow.Date; // true
Vadim
1

Podejście wykorzystujące 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
źródło
0

W rzeczywistości data będzie typu Object. Ale możesz sprawdzić, czy obiekt ma getMonthmetodę i czy można ją wywoływać.

function getFormatedDate(date) {
    if (date && date.getMonth && date.getMonth.call) {
       var month = date.getMonth();
    }
}
vartec
źródło
2
Odpowiedź Christopha jest dokładniejsza. Posiadanie właściwości „call” niekoniecznie oznacza, że ​​jest to funkcja!
Chetan Sastry
-1

Możemy to również sprawdzić za pomocą poniższego kodu

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

wprowadź opis zdjęcia tutaj

Bieg
źródło
Konstruktor function Date() {/*...*/}jest również Date. Tj. Zwykłe porównanie funkcji konstruktora jest zbyt podatne na błędy, co często skutkuje fałszywymi trafieniami.
Pomiń
-1

Zainspirowane tą odpowiedzią , to rozwiązanie działa w moim przypadku (musiałem sprawdzić, czy wartość otrzymana z API jest datą, czy nie):

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

W ten sposób, jeśli jest to dowolny ciąg losowy pochodzący od klienta lub dowolnego innego obiektu, możesz dowiedzieć się, czy jest to obiekt podobny do daty.

Mohammad Ganji
źródło
-2

Nie możesz po prostu użyć

function getFormatedDate(date) {
    if (date.isValid()) {
       var month = date.GetMonth();
    }
}
Gderliwy
źródło
1
Nie, isValidmetoda ma tylko obiekt daty
nikk wong 14.04.17
2
@grumpy @nikkwong Nie i nie. Standardowy obiekt daty nie ma isValid. Tylko moment.js ma taki interfejs API.
Boghyon Hoffmann