Обнаружение "недопустимой даты" экземпляра 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';