Обнаружение "недопустимой даты" экземпляра Date в JavaScript

Я хотел бы сказать разницу между действительными и недействительными объектами даты в JS, но не мог понять, как:

var d = new Date("foo");
console.log(d.toString()); // shows 'Invalid Date'
console.log(typeof d); // shows 'object'
console.log(d instanceof Date); // shows 'true'

Любые идеи для написания isValidDate функционировать?

  • Эш рекомендуется Date.parse для разбора строк даты, который дает авторитетный способ проверить, является ли строка даты действительной.
  • Что бы я предпочел, если это возможно, это чтобы мой API принимал экземпляр Date и мог проверять / утверждать, действителен ли он или нет. Решение Borgar делает это, но мне нужно протестировать его в разных браузерах. Мне также интересно, есть ли более элегантный способ.
  • Эш заставил меня задуматься о том, чтобы мой API не принимал Date В любом случае, это будет проще всего проверить.
  • Боргар предложил провести тестирование Date экземпляр, а затем тестирование на Dateзначение времени. Если дата недействительна, значение времени NaN, Я проверил с ECMA-262, и это поведение в стандарте, который именно то, что я ищу.

56 ответов

Решение

Вот как бы я это сделал:

if (Object.prototype.toString.call(d) === "[object Date]") {
  // it is a date
  if (isNaN(d.getTime())) {  // d.valueOf() could also work
    // date is not valid
  } else {
    // date is valid
  }
} else {
  // not a date
}

Обновление [2018-05-31]: Если вас не интересуют объекты Date из других контекстов JS (внешних окон, фреймов или фреймов), эта более простая форма может оказаться предпочтительной:

function isValidDate(d) {
  return d instanceof Date && !isNaN(d);
}

Вместо того, чтобы использовать new Date() вы должны использовать:

var timestamp = Date.parse('foo');

if (isNaN(timestamp) == false) {
  var d = new Date(timestamp);
}

Date.parse() возвращает отметку времени, целое число, представляющее количество миллисекунд с 01 января 1970 года. Он вернется NaN если он не может разобрать предоставленную строку даты.

Вы можете проверить действительность Date объект d с помощью

d instanceof Date && isFinite(d)

Чтобы избежать межкадровых проблем, можно заменить instanceof проверить с

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

Вызов getTime() так как в ответе Боргара нет необходимости, так как isNaN() а также isFinite() оба неявно преобразуются в число.

Кратчайший ответ, чтобы проверить действительную дату

if(!isNaN(date.getTime()))

Мое решение - просто проверить, есть ли у вас действительный объект даты:

Реализация

Date.prototype.isValid = function () {
    // An invalid date object returns NaN for getTime() and NaN is the only
    // object not strictly equal to itself.
    return this.getTime() === this.getTime();
};  

использование

var d = new Date("lol");

console.log(d.isValid()); // false

d = new Date("2012/09/11");

console.log(d.isValid()); // true

Прочитав до сих пор все ответы, я буду часто давать самые простые ответы.

В каждом решении здесь упоминается вызов date.getTime(). Однако в этом нет необходимости, поскольку преобразование даты в число по умолчанию заключается в использовании значения getTime (). Да, ваша проверка типа будет жаловаться. :) И ОП ясно знает, что у них есть Date объект, поэтому не нужно проверять и это.

Чтобы проверить неверную дату:

      isNaN(date)

Чтобы проверить действительную дату:

      !isNaN(date)

Я видел некоторые ответы, которые очень близко подошли к этому маленькому фрагменту.

JavaScript способ:

function isValidDate(dateString){ return new Date(dateString).toString() !== 'Invalid Date'; }
isValidDate(new Date('WTH'));

TypeScript способ:

const isValidDate = dateString => new Date(dateString).toString() !== 'Invalid Date';
isValidDate(new Date('WTH'));

Вы можете просто использовать moment.js

Вот пример:

var m = moment('2015-11-32', 'YYYY-MM-DD');
m.isValid(); // false

Раздел валидации в документации вполне понятен.

А также, следующие флаги синтаксического анализа приводят к неверной дате:

  • overflow: Переполнение поля даты, например, 13-го месяца, 32-го дня месяца (или 29-го февраля для не високосных лет), 367-го дня года и т. Д. Переполнение содержит индекс недопустимой единицы соответствовать #invalidAt (см. ниже); -1 означает отсутствие переполнения.
  • invalidMonth: Неверное название месяца, например, момент ("Март", "ММММ"). Содержит недопустимую строку месяца, либо нуль.
  • empty: Входная строка, которая не содержит ничего для анализа, например момент ("это чушь"); Boolean.
  • И т.п.

Источник: http://momentjs.com/docs/

Хотелось бы отметить, что виджет DatePicker пользовательского интерфейса jQuery имеет очень хороший метод утилиты проверки даты, который проверяет формат и действительность (например, даты 01/33/2013 не допускаются).

Даже если вы не хотите использовать виджет datepicker на своей странице в качестве элемента пользовательского интерфейса, вы всегда можете добавить его библиотеку.js на свою страницу и затем вызвать метод validator, передав в него значение, которое вы хотите проверить. Чтобы сделать жизнь еще проще, в качестве входных данных используется строка, а не объект JavaScript Date.

Смотрите: http://api.jqueryui.com/datepicker/

Это не перечислено как метод, но это там - как служебная функция. Найдите на странице "parsedate", и вы найдете:

$.datepicker.parseDate (формат, значение, настройки) - извлечение даты из строкового значения в указанном формате.

Пример использования:

var stringval = '01/03/2012';
var testdate;

try {
  testdate = $.datepicker.parseDate('mm/dd/yy', stringval);
             // Notice 'yy' indicates a 4-digit year value
} catch (e)
{
 alert(stringval + ' is not valid.  Format must be MM/DD/YYYY ' +
       'and the date value must be valid for the calendar.';
}

(Более подробную информацию об указании форматов даты можно найти по адресу http://api.jqueryui.com/datepicker/).

В приведенном выше примере вы не увидите предупреждающее сообщение, поскольку "01/03/2012" является датой, действующей в календаре, в указанном формате. Однако, например, если вы сделали 'stringval' равным '13/04/2013', вы получите предупреждающее сообщение, поскольку значение '13/04/2013' недействительно для календаря.

Если переданное строковое значение успешно проанализировано, значением 'testdate' будет объект Javascript Date, представляющий переданное строковое значение. Если нет, это было бы неопределенным.

// check whether date is valid
var t = new Date('2011-07-07T11:20:00.000+00:00x');
valid = !isNaN(t.valueOf());

Мне очень понравился подход Кристофа (но мне не хватило репутации, чтобы проголосовать). Для моего использования я знаю, что у меня всегда будет объект Date, поэтому я просто расширил дату с помощью метода valid().

Date.prototype.valid = function() {
  return isFinite(this);
}

Теперь я могу просто написать это, и это гораздо более наглядно, чем просто проверка isFinite в коде...

d = new Date(userDate);
if (d.valid()) { /* do stuff */ }

Я использую следующий код для проверки значений года, месяца и даты.

function createDate(year, month, _date) {
  var d = new Date(year, month, _date);
  if (d.getFullYear() != year 
    || d.getMonth() != month
    || d.getDate() != _date) {
    throw "invalid date";
  }
  return d;
}

Для деталей, обратитесь к Проверке даты в JavaScript

Вы можете проверить действительный формат txDate.value с этим scirpt. если он был в неправильном формате, объект Date не был создан и возвращал ноль в dt .

 var dt = new Date(txtDate.value)
 if (isNaN(dt))

И как @MiF's предложил вкратце

 if(isNaN(new Date(...)))

Почему я пишу 48-й ответ после того, как многие пытались до меня?

Для проверки, является ли это объектом даты, а затем действительным объектом даты - очень просто:

      return x instanceof Date && !!x.getDate();

Теперь о синтаксическом анализе даты Текст: в большинстве решений используются Date.parse() или «new Date()», оба из которых имеют проблемы. JavaScript анализирует самые разные форматы, а также зависит от локализации. Например, такие строки, как «1» и «blah-123», будут анализироваться как допустимая дата.

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

Если вы просмотрели до конца стопки, надеюсь, кому-то из вас понравится этот мертвенно простой метод проверки строки даты. Уловка состоит в том, чтобы использовать простое регулярное выражение для устранения нежелательных форматов, а затем, если это удается, использовать Date.parse(). Неудачный синтаксический анализ приводит к NaN, что является «ложным». Знак "!!" преобразует это в логическое «ложь».

Здесь уже слишком много сложных ответов, но достаточно простой строки (ES5):

Date.prototype.isValid = function (d) { return !isNaN(Date.parse(d)) } ;

или даже в ES6:

Date.prototype.isValid = d => !isNaN(Date.parse(d));

Это просто работает для меня

new Date('foo') == 'Invalid Date'; //is true

Однако это не сработало

new Date('foo') === 'Invalid Date'; //is false

Для проектов Angular.js вы можете использовать:

angular.isDate(myDate);

Ни один из этих ответов не сработал для меня (проверено в Safari 6.0) при попытке проверить дату, такую ​​как 31.02.2012, однако, они работают нормально при попытке установить любую дату больше 31.

Поэтому мне пришлось немного перебрать силу. Предполагая, что дата в формате mm/dd/yyyy, Я использую ответ @broox:

Date.prototype.valid = function() {
    return isFinite(this);
}    

function validStringDate(value){
    var d = new Date(value);
    return d.valid() && value.split('/')[0] == (d.getMonth()+1);
}

validStringDate("2/29/2012"); // true (leap year)
validStringDate("2/29/2013"); // false
validStringDate("2/30/2012"); // false

Отличное решение! Включено в мою библиотеку вспомогательных функций, теперь это выглядит так:

Object.isDate = function(obj) {
/// <summary>
/// Determines if the passed object is an instance of Date.
/// </summary>
/// <param name="obj">The object to test.</param>

    return Object.prototype.toString.call(obj) === '[object Date]';
}

Object.isValidDate = function(obj) {
/// <summary>
/// Determines if the passed object is a Date object, containing an actual date.
/// </summary>
/// <param name="obj">The object to test.</param>

    return Object.isDate(obj) && !isNaN(obj.getTime());
}

Я редко рекомендую библиотеки, если без них можно обойтись. Но, учитывая обилие ответов, кажется, стоит отметить, что популярная библиотека date-fns имеет функцию isValid .

Date.prototype.toISOString бросает RangeError (по крайней мере, в Chromium и Firefox) на недопустимые даты. Вы можете использовать его как средство проверки и может не потребоваться isValidDate как таковой (EAFP). В противном случае это:

function isValidDate(d)
{
  try
  {
    d.toISOString();
    return true;
  }
  catch(ex)
  {
    return false;    
  }    
}

Вы можете попробовать что-то вроде этого:

      const isDate = (val) => !isNaN(new Date(val).getTime());

Ни одно из вышеперечисленных решений не помогло мне.

function validDate (d) {
        var date = new Date(d);
        var day = ""+date.getDate();
        if( day.length == 1)day = "0"+day;
        var month = "" +( date.getMonth() + 1);
        if( month.length == 1)month = "0"+month;
        var year = "" + date.getFullYear();

        return ((month + "/" + day + "/" + year) == d);
    }

код выше будет видеть, когда JS превращает 31 марта 2012 в 02/02/2012, что он не действителен

IsValidDate: function(date) {
        var regex = /\d{1,2}\/\d{1,2}\/\d{4}/;
        if (!regex.test(date)) return false;
        var day = Number(date.split("/")[1]);
        date = new Date(date);
        if (date && date.getDate() != day) return false;
        return true;
}

NaN является ложным. invalidDateObject.valueOf() имеет значение NaN.

      const d = new Date('foo');
if (!d.valueOf()) {
  console.error('Not a valid date object');
}
else {
  // act on your validated date object
}

Несмотря на то, что valueOf() функционально эквивалентен getTime(), я считаю его более подходящим в данном контексте.

Я написал эту функцию. Передайте ему строковый параметр, и он будет определять, является ли это действительной датой или нет, основываясь на этом формате "дд / мм / гггг".

вот тест

вход: "хахаха", вывод: ложь.

вход: "29/2/2000", выход: true.

вход: "29/2/2001", выход: ложь.

function isValidDate(str) {
    var parts = str.split('/');
    if (parts.length < 3)
        return false;
    else {
        var day = parseInt(parts[0]);
        var month = parseInt(parts[1]);
        var year = parseInt(parts[2]);
        if (isNaN(day) || isNaN(month) || isNaN(year)) {
            return false;
        }
        if (day < 1 || year < 1)
            return false;
        if(month>12||month<1)
            return false;
        if ((month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) && day > 31)
            return false;
        if ((month == 4 || month == 6 || month == 9 || month == 11 ) && day > 30)
            return false;
        if (month == 2) {
            if (((year % 4) == 0 && (year % 100) != 0) || ((year % 400) == 0 && (year % 100) == 0)) {
                if (day > 29)
                    return false;
            } else {
                if (day > 28)
                    return false;
            }      
        }
        return true;
    }
}

Вдохновленный подходом Боргара, я убедился, что код не только проверяет дату, но и на самом деле удостоверяется, что дата является реальной датой, то есть такие даты, как 31/09/2011 и 29/02/2011, недопустимы.

function(dateStr) {
    s = dateStr.split('/');
    d = new Date(+s[2], s[1]-1, +s[0]);
    if (Object.prototype.toString.call(d) === "[object Date]") {
        if (!isNaN(d.getTime()) && d.getDate() == s[0] && 
            d.getMonth() == (s[1] - 1)) {
            return true;
        }
    }
    return "Invalid date!";
}

Простое и элегантное решение:

const date = new Date(`${year}-${month}-${day} 00:00`)
const isValidDate = (Boolean(+date) && date.getDate() == day)

источники:

[1] https://medium.com/@esganzerla/simple-date-validation-with-javascript-caea0f71883c

[2] Неправильная дата отображается в новой дате () в JavaScript.

Готовая функция, основанная на ответе с самым высоким рейтингом:

  /**
   * Check if date exists and is valid.
   *
   * @param {String} dateString Date in YYYY-mm-dd format.
   */
  function isValidDate(dateString) {
  var isValid = false;
  var date;

  date =
    new Date(
      dateString);

  if (
    Object.prototype.toString.call(
      date) === "[object Date]") {

    if (isNaN(date.getTime())) {

      // Date is unreal.

    } else {
      // Date is real if month and day match each other in date and string (otherwise may be shifted):
      isValid =
        date.getUTCMonth() + 1 === dateString.split("-")[1] * 1 &&
        date.getUTCDate() === dateString.split("-")[2] * 1;
    }
  } else {
    // It's not a date.
  }

  return isValid;
}

Вы можете конвертировать свою дату и время в миллисекунды getTime()

этот getTime() Метод return Не число NaN когда не действует

if(!isNaN(new Date("2012/25/255").getTime()))
  return 'valid date time';
  return 'Not a valid date time';
Другие вопросы по тегам