Как проверить, является ли объект датой?

601

У меня есть раздражающая ошибка на веб-странице:

date.GetMonth () не является функцией

Итак, я полагаю, что я делаю что-то не так. Переменная dateне является объектом типа Date. Как я могу проверить тип данных в Javascript? Я пытался добавить if (date), но это не работает.

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

Итак, если я хочу написать защитный код и предотвратить форматирование даты (не одной), как мне это сделать?

Спасибо!

ОБНОВЛЕНИЕ: я не хочу проверять формат даты, но я хочу быть уверен, что параметр, переданный методу, getFormatedDate()имеет тип Date.

Мартин
источник
В случае, если также необходимо проверить, не является ли датаInvalid Date : stackoverflow.com/a/44198641/5846045
Boghyon Hoffmann

Ответы:

1110

Как альтернатива печатанию утки через

typeof date.getMonth === 'function'

вы можете использовать instanceofоператор, т. е. но он также вернет true для недопустимых дат, например new Date('random_string'), также является экземпляром Date

date instanceof Date

Это не удастся, если объекты будут переданы через границы кадра.

Обходным путем для этого является проверка класса объекта с помощью

Object.prototype.toString.call(date) === '[object Date]'
Christoph
источник
29
Из интереса знаете ли вы причину этого сбоя при переходе через границы кадра?
Симон Лишке
85
@Simon: глобалы JS являются локальными для текущего глобального объекта (он же windowили self); разные фреймы имеют свои собственные глобальные объекты, и их свойства (т. е. глобальные) относятся к разным объектам: Dateв frame1 есть другой объект функции, чем Dateв frame2; то же самое верно для Date.prototype, что является причиной instanceofсбоя: Date.prototypeиз frame1 не является частью цепочки прототипов Dateэкземпляров из frame2
Кристоф
9
Кристоф, что ты называешь "рамкой"? IFRAME, каждый кадр в FRAMESET или что-то еще (я имею в виду JS-специфический, а не HTML-объект)?
Пол
12
new Date('something') instanceof Dateвозвращается trueв Chrome. Это не сработает тогда.
крильгар
12
Обнаружение объекта типа Date (в отличие от простого Object или строки) и проверка объекта, которым вы ожидаете быть Date, - это две разные задачи. Существует ряд ситуаций, когда входные данные для вашей функции могут быть одного из нескольких типов данных. В моем случае я могу доверять тому, что любой объект Date, который я получаю, является действительным (он поступает не напрямую от клиента). Если проверка связана с проблемой, вот публикация с несколькими вариантами. stackoverflow.com/questions/1353684/…
Майкл Блэкберн
125

Вы можете использовать следующий код:

(myvar instanceof Date) // returns true or false
SF_dev
источник
6
Почему это не принятый или более одобренный ответ? Простая проверка, имеет ли date свойство .getMonth, может привести к ложному срабатыванию.
дореми
24
instanceof может вызвать ложные отрицания, см. комментарий Кристофа к своему собственному ответу.
Марко Мариани
2
@doremi Вот демонстрация instanceofзапуска ложного негатива: jsbin.com/vufufoq/edit?html,js,console
Богьон Хоффманн,
69

Чтобы проверить, является ли значение допустимым типом стандартного объекта JS-date, вы можете использовать этот предикат:

function isValidDate(date) {
  return date && Object.prototype.toString.call(date) === "[object Date]" && !isNaN(date);
}
  1. dateпроверяет , не был ли параметр а falsy значение ( undefined, null, 0, ""и т.д ..)
  2. Object.prototype.toString.call(date)возвращает нативное строковое представление заданного типа объекта - в нашем случае "[object Date]". Поскольку date.toString()переопределяет его родительский метод , нам нужно .callили .applyметод Object.prototypeнепосредственно из которого ..
    • Обходит определенный пользователем тип объекта с тем же именем конструктора (например, «Дата»)
    • Работает в разных контекстах JS (например, iframes) в отличие отinstanceof или Date.prototype.isPrototypeOf.
  3. !isNaN(date)наконец проверяет, не было ли значение Invalid Date.
Богьон Хоффманн
источник
1
Wow isNaNможно использовать для проверки Date. Это какой-то уровень безразличия в PHP.
Ник
@ Ник дата хотя число.
Иосия
@Josiah Ну, конечно, убрав все контексты есть отметка о времени там: typeof Date.now() === "number", но: typeof new Date() === "object". Более реалистично, однако, дата - это время и место в пространстве.
Ник
39

Функция есть getMonth(), нет GetMonth().

В любом случае, вы можете проверить, имеет ли объект свойство getMonth, выполнив это. Это не обязательно означает, что объект является Date, просто любой объект, который имеет свойство getMonth.

if (date.getMonth) {
    var month = date.getMonth();
}
Четан Шастри
источник
3
Проверьте, может ли это быть вызвано:if (date.getMonth && typeof date.getMonth === "function") {...}
Aloso
20

Как указано выше, вероятно, проще всего просто проверить, существует ли функция перед ее использованием. Если вам действительно важно, что это Dateне объект с getMonth()функцией, попробуйте следующее:

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

Это создаст либо клон значения, если оно есть Date, либо создаст недопустимую дату. Затем вы можете проверить, является ли значение новой даты недействительным или нет.

bdukes
источник
1
Это сработало для меня, спасибо. Однако, если вы передадите одну цифру, такую ​​как 0 или 1, это будет считаться действительной датой ... есть мысли?
Рикардо Санчес
Это верно, @RicardoSanchez. Вы, вероятно, хотите использовать принятый ответ ( Object.prototype.toString.call(value) === '[object Date]'), если возможно, что вы будете получать цифры. Метод в этом ответе действительно говорит вам, можно ли valueпреобразовать в a Date.
bdukes
18

Для всех типов я подготовил функцию-прототип Object. Это может быть полезно для вас

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

Теперь вы можете проверить любой тип как это:

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

[ Изменить март 2013 ], основываясь на прогрессивном понимании, это лучший метод:

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
источник
10

UnderscoreJS и Lodash имеют функцию, .isDate()которая называется именно то, что вам нужно. Стоит посмотреть на их соответствующие реализации: Lodash isDate , UnderscoreJs

avalanche1
источник
8

Лучший способ, который я нашел, это:

!isNaN(Date.parse("some date test"))
//
!isNaN(Date.parse("22/05/2001"))  // true
!isNaN(Date.parse("blabla"))  // false
jspassov
источник
Это не работает Ваша истинная линия на самом деле ложна, и вопрос в том, чтобы проверить, является ли объект объектом даты ...
Клинт
1
Ответ @jspassov более точен, если строка является датой или нет. Что я искал. Спасибо!!
Анант
Это лучший ответ для простой проверки, является ли строка датой или нет
Джеймс
4

Вместо всех обходных путей вы можете использовать следующее:

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

Я нашел этот взлом лучше!

itsHarshad
источник
3

Вы можете проверить, существует ли функция, специфичная для объекта Date:

function getFormatedDate(date) {
    if (date.getMonth) {
        var month = date.getMonth();
    }
}
Powerlord
источник
2

Также вы можете использовать короткую форму

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

или что-то вроде этого:

(toString.call(date)) == 'Date'
Павло
источник
2

Я использовал гораздо более простой способ, но не уверен, доступен ли он только в ES6 или нет.

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"

Тем не менее, это не будет работать с нулевым или неопределенным, поскольку у них нет конструктора.

mjwrazor
источник
Любой изготовленный на заказ объект с именем конструктора «Date» "Date"тоже возвращает, что так же рискованно, как просто проверка, имеет ли параметр getMonthсвойство.
Богьон Хоффманн
2
@boghyon звучит так, как будто кто-то создает объект с именем конструктора уже предопределенной стандартной библиотеки Javascript, в первую очередь он не следует передовым методам. Это похоже на загрузку lodash, создание собственного модуля lodash и ожидание того, что все будет работать.
mjwrazor
1

Эта функция вернет, trueесли это Date или falseиначе:

function isDate(myDate) {
    return myDate.constructor.toString().indexOf("Date") > -1;
} 
Jahid
источник
1
isDate(new (function AnythingButNotDate(){ })())возвращаетсяtrue
Boghyon Hoffmann
1

Еще один вариант:

Date.prototype.isPrototypeOf(myDateObject)
Вадим
источник
Хороший и короткий! Но, к сожалению, это та же проблема, что иinstanceof .
Богьон Хоффманн
@ BoghyonHoffmann в случае iFrame это может выглядеть так: iWindow.Date.prototype.isPrototypeOf(iWindow.date); // true iWindow.date instanceof iWindow.Date; // true
Вадим
1

Подход с использованием 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
источник
0

На самом деле дата будет иметь тип Object. Но вы можете проверить, есть ли у объекта getMonthметод и можно ли его вызвать.

function getFormatedDate(date) {
    if (date && date.getMonth && date.getMonth.call) {
       var month = date.getMonth();
    }
}
Vartec
источник
2
Ответ Кристофа более точный. Наличие свойства 'call' не обязательно означает, что это функция!
Четан Шастри
-1

Мы также можем подтвердить это с помощью кода ниже

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

введите описание изображения здесь

Arun
источник
Конструктор function Date() {/*...*/}также Date. Т.е. простое сравнение функции конструктора слишком подвержено ошибкам, что часто приводит к ложным срабатываниям. Обход пользовательского типа объекта с помощью stackoverflow.com/a/44198641/5846045
Богьон Хоффманн
-1

Вдохновленный этим ответом , это решение работает в моем случае (мне нужно было проверить, является ли значение, полученное из API, датой или нет):

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

Таким образом, если это какая-то случайная строка, исходящая от клиента или любого другого объекта, вы можете узнать, является ли это объектом типа даты.

Мохаммад Ганджи
источник
-2

Не могли бы вы просто использовать

function getFormatedDate(date) {
    if (date.isValid()) {
       var month = date.GetMonth();
    }
}
Сердитый
источник
1
Нет, только объект даты имеет isValidметод
Никк Вонг
2
@ grumpy @nikkwong Нет и нет. Стандартный объект даты не имеет isValid. Только момент.js имеет такой API.
Богьон Хоффманн