在JavaScript中检测"无效日期"日期实例

ori*_*rip 1381 javascript date

我想告诉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'
Run Code Online (Sandbox Code Playgroud)

编写isValidDate函数的任何想法?

  • Ash建议Date.parse用于解析日期字符串,它提供了一种检查日期字符串是否有效的权威方法.
  • 如果可能的话,我希望我的API接受一个Date实例,并且能够检查/断言它是否有效.Borgar的解决方案就是这样做的,但我需要跨浏览器进行测试.我也想知道是否有更优雅的方式.
  • Ash让我觉得根本没有我的API接受Date实例,这最容易验证.
  • Borgar建议测试一个Date实例,然后测试它Date的时间值.如果日期无效,则时间值为NaN.我用ECMA-262检查了这个行为是标准的,这正是我正在寻找的.

Bor*_*gar 1191

我是这样做的:

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
}
Run Code Online (Sandbox Code Playgroud)

更新[2018-05-31]:如果您不关心来自其他JS上下文(外部窗口,框架或iframe)的Date对象,则可以首选这种更简单的形式:

function isValidDate(d) {
  return d instanceof Date && !isNaN(d);
}
Run Code Online (Sandbox Code Playgroud)

  • 你甚至不需要`d.getTime`只是`isNan(d)` (58认同)
  • instanceof在帧之间中断.鸭子打字也可以正常工作:validDate == d && d.getTime &&!isNaN(d.getTime()); - 由于问题是一般的效用函数,我更喜欢更严格. (21认同)
  • @Borgar,刚刚找到我的答案:"在多帧DOM环境中编写脚本问题时出现问题.简而言之,在一个iframe中创建的Array对象不与另一个iframe中创建的数组共享[[Prototype]]它们的构造函数是不同的对象,因此instanceof和constructor检查都失败了." (11认同)
  • 可以像这样简化:`d instanceof Date &&!isNaN(d.getTime())` (6认同)
  • 问题是关于 *javascript* 而不是 Typescript 提出的。`isNaN` 的内置类型仅包括“正确”的参数类型(即“number”),而不包括可以轻松强制为正确类型的类型(如“string”或“Date”)。Typescript 的全部“要点”是避免 JS 运行时让您逃脱的那种快速而松散的鲁莽行为。(恕我直言,传达意图的最佳方式是“isNan(d.getTime())”。) (4认同)
  • 是的,@Jerry,“有效日期对象”和“有效日期”不是一回事:stackoverflow.com/a/13897331/27388 (3认同)
  • 根本不起作用。这将接受使用任何日/月/年组合的任何日期对象,即使它无效。 (3认同)
  • 谢谢你的回答,但我想强调@Borgar和@blueprintChris评论:如果我解析数字`1`例如我仍然有一个有效的日期导致'2001年1月1日00:00:00`这确实是约会,但就我的申请而言,它完全没用.因此,至少在我的案例中需要更多的输入验证.这个答案验证了`dateObject`而不是`Date`! (3认同)
  • 这将触发 TypeScript 错误,“TS2345:‘日期’类型的参数无法分配给‘数字’类型的参数”。 (3认同)
  • 该函数返回日期数小于 32 的任何日期的有效日期。因此 `2021-02-30` 是有效日期 `2021-04-31` 也是有效日期! (3认同)
  • 尝试第二个例子,它对我没有用。我需要将第二部分更改为: `!isNaN(d.getTime());` (2认同)
  • @DanDascalescu 这就是我的做法 `isNaN(date.getTime())` (2认同)

Ash*_*Ash 244

而不是使用new Date()你应该使用:

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

if (isNaN(timestamp) == false) {
  var d = new Date(timestamp);
}
Run Code Online (Sandbox Code Playgroud)

Date.parse()返回一个时间戳,一个整数,表示自01/Jan/1970以来的毫秒数.NaN如果它无法解析提供的日期字符串,它将返回.

  • -1 Dunno为什么这么多的投票,`Date.parse`是依赖于实现的,绝对不能被信任解析一般的日期字符串.在流行的浏览器中没有正确解析的单一格式,更不用说所有使用的格式(尽管最终ISO8601格式[在ES5中指定](http://es5.github.com/#x15.9.1.15)应该是好). (114认同)
  • 这个测试在 Chrome 中会失败。例如,Chrome 中的 Date.parse('AAA-0001') 给了我一个数字。 (3认同)
  • 如果你使用 `new Date('foo')`,它基本上等同于 `Date.parse('foo')` 方法。请参阅:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#Timestamp_string 所以@RobG 所说的,它也适用于它。 (2认同)
  • 失败...检测所有数值 (2认同)

Chr*_*oph 102

您可以检查的有效性Date对象d通过

d instanceof Date && isFinite(d)
Run Code Online (Sandbox Code Playgroud)

为避免跨框架问题,可以用instanceof支票代替支票

Object.prototype.toString.call(d) === '[object Date]'
Run Code Online (Sandbox Code Playgroud)

要在通话getTime()Borgar的回答是不必要的,因为isNaN()isFinite()两个隐式转换为数字.

  • @Tintin:这就是`isFinite()`的含义-`toString.call()`只是检查中`instanceof`部分的替代品 (2认同)
  • @kristianp实际上它可能并且甚至可能是ECMAScript规范的一部分。但是,是的,这看起来很丑。 (2认同)

Ash*_*rke 82

我的解决方案是简单地检查您是否获得了有效的日期对象:

履行

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();
};  
Run Code Online (Sandbox Code Playgroud)

用法

var d = new Date("lol");

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

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

console.log(d.isValid()); // true
Run Code Online (Sandbox Code Playgroud)

  • `isNaN`是一种更明确的测试NaN的方法 (25认同)
  • 我测试了我在这里找到的3个主要解决方案的性能.恭喜,你是赢家!http://jsperf.com/detecting-an-invalid-date (7认同)
  • 因为我尊重underscore.js这引发了一些研究.`isNaN("a")=== true`,而`("a"!=="a")=== false`.值得思考.+1 (3认同)
  • @Ali这是有效的日期对象。`new Date(“ 02-31-2000”)// 2000年3月2日,星期四00:00:00 GMT + 0000(GMT标准时间)。如果要将字符串传递给日期构造函数,则必须传递标准化字符串才能获得可靠的结果。具体来说,“字符串应采用Date.parse()方法可识别的格式”。https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Date (2认同)

abh*_*006 64

检查有效日期的最短答案

if(!isNaN(date.getTime()))
Run Code Online (Sandbox Code Playgroud)

  • 唯一的问题是如果 date 不是 Date 类型;你得到一个 JS 错误。 (3认同)
  • 对,就像8年前的其他答案一样.:P /sf/answers/94776181/ (3认同)
  • 只要他们使用 `var date = new Date(str)`,那么这个答案将是最短和最合适的。 (3认同)

Ste*_*gin 58

在阅读了到目前为止的每个答案后,我将提供最简单的答案。

这里的每个解决方案都提到调用date.getTime(). 但是,这不是必需的,因为从日期到数字的默认转换是使用 getTime() 值。是的,你的类型检查会抱怨。:) OP 清楚地知道他们有一个Date对象,所以也不需要测试它。

要测试无效日期:

isNaN(date)
Run Code Online (Sandbox Code Playgroud)

要测试有效日期:

!isNaN(date)
Run Code Online (Sandbox Code Playgroud)

或(感谢 icc97 提供此替代方案)

isFinite(date) 
Run Code Online (Sandbox Code Playgroud)

或打字稿(感谢 pat-migliaccio)

isFinite(+date) 
Run Code Online (Sandbox Code Playgroud)

  • 对于 TypeScript,为了避免类型错误,您可以使用“isNaN(+date)”将日期强制转换为数字。 (3认同)
  • @icc97 我将您的建议添加到解决方案中。 (2认同)

Yve*_* M. 43

你可以简单地使用moment.js

这是一个例子:

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

文档中的验证部分非常清楚.

而且,以下解析标志会导致无效日期:

  • overflow:日期字段的溢出,例如第13个月,第32个月(或非闰年2月29日),一年中第367天等.溢出包含无效单位的索引匹配#invalidAt(见下文); -1表示没有溢出.
  • invalidMonth:无效的月份名称,例如时刻('Marbruary','MMMM');. 包含无效的月份字符串本身,否则为null.
  • empty:包含无法解析的输入字符串,例如moment('this is nonsense');. 布尔.
  • 等等.

资料来源:http://momentjs.com/docs/

  • 最好的解决方案,非常容易实现,适用于任何格式(我的情况是dd/MM/yyyy),也知道闰年并且不会将无效日期(即29/02/2015)转换为有效日期(即30/03/2015).要检查formad dd/MM/yyyy中的日期,我只需要使用`moment("11/06/1986","DD/MM/YYYY").isValid();` (6认同)
  • 使用 moment.js 可能很简单,但开销巨大。这个图书馆是巨大的。我对你的回答投了反对票。 (5认同)
  • 这个Moment的使用已被弃用:( (2认同)
  • 真糟糕。moment.js 仍然没有解决我的 Chrome 特定问题,即它从短语中猜测正确的日期。m = 时刻(“鲍勃 2015”); m.isValid(); // 真的 (2认同)
  • 此用途尚未折旧.不使用格式字符串的调用时刻(输入)将被折旧(除非输入是ISO格式的). (2认同)
  • 处理许多日期时,此方法可能非常慢.在这些情况下更好地使用正则表达式. (2认同)
  • @GridTrekkor 我希望看到这个答案。不要忘记处理闰年。 (2认同)

Mat*_*ell 37

想提一下jQuery UI DatePicker小部件有一个非常好的日期验证器实用程序方法,它检查格式和有效性(例如,不允许01/33/2013日期).

即使您不希望将页面上的datepicker小部件用作UI元素,也可以始终将其.js库添加到页面,然后调用验证器方法,将要验证的值传递给它.为了让生活更轻松,它需要一个字符串作为输入,而不是JavaScript Date对象.

请参阅:http://api.jqueryui.com/datepicker/

它不是作为一种方法列出的,而是它作为一种效用函数.在页面中搜索"parsedate",你会发现:

$ .datepicker.parseDate(format,value,settings) - 从具有指定格式的字符串值中提取日期.

用法示例:

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.';
}
Run Code Online (Sandbox Code Playgroud)

(更多信息请在http://api.jqueryui.com/datepicker/#utility-parseDate上找到指定日期格式)

在上面的示例中,您将看不到警报消息,因为'01/03/2012'是指定格式的日历有效日期.但是,如果您将'stringval'等于'13/04/2013',则会收到警报消息,因为值'13/04/2013'不是日历有效的.

如果成功解析了传入的字符串值,则'testdate'的值将是表示传入的字符串值的Javascript Date对象.如果没有,它将是未定义的.

  • Upvote是第一个使用非英语/语言环境日期格式的答案. (3认同)

bro*_*oox 24

我真的很喜欢克里斯托夫的做法(但没有足够的声誉来投票).对于我的使用,我知道我将永远有一个Date对象,所以我只使用valid()方法扩展日期.

Date.prototype.valid = function() {
  return isFinite(this);
}
Run Code Online (Sandbox Code Playgroud)

现在我可以写这个,它比仅仅在代码中检查isFinite更具描述性......

d = new Date(userDate);
if (d.valid()) { /* do stuff */ }
Run Code Online (Sandbox Code Playgroud)

  • 扩展原型?这是一个很大的JavaScript不,不! (10认同)

far*_*idz 22

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

  • 它是两行而不是丑陋的嵌套if语句. (11认同)
  • 它是相同的[@Borgar写的](http://stackoverflow.com/a/1353711/505893)2年前......什么是新的? (5认同)
  • 警告:空值作为有效值传递 (2认同)

Vij*_*ale 16

在我之前有这么多人尝试过之后,为什么我还要写第 48 个答案?大多数答案都是部分正确的,并且并不适用于所有情况,而其他答案则不必要地冗长和复杂。下面是一个非常简洁的解决方案。这将检查它是否是Date类型,然后检查是否是有效的日期对象:

return x instanceof Date && !!x.getDate();
Run Code Online (Sandbox Code Playgroud)

现在解析日期文本:大多数解决方案使用 Date.parse() 或“new Date()”——这两种方法都会在某些情况下失败并且可能很危险。JavaScript 可以解析多种格式,并且还依赖于本地化。例如,“1”和“blah-123”等字符串将解析为有效日期。

还有一些帖子要么使用大量代码,要么使用一英里长的正则表达式,要么使用第三方框架。

这是验证日期字符串的非常简单的方法。

return x instanceof Date && !!x.getDate();
Run Code Online (Sandbox Code Playgroud)
function isDate(txt) {
   var matches = txt.match(/^\d?\d\/(\d?\d)\/\d{4}$/); //Note: "Day" in the RegEx is parenthesized
   return !!matches && !!Date.parse(txt) && new Date(txt).getDate()==matches[1];
}
Run Code Online (Sandbox Code Playgroud)

isDate 的第一行使用简单的正则表达式解析输入文本,以验证日期格式 mm/dd/yyyy 或 m/d/yyyy。对于其他格式,您需要相应地更改正则表达式,例如,对于 dd-mm-yyyy,正则表达式变为/^(\d?\d)-\d?\d-\d{4}$/

如果解析失败,“matches”为空,否则它存储月份中的日期。第二行进行更多测试以确保其是有效日期并消除像 9/31/2021 这样的情况(JavaScript 允许)。最后请注意,双击 (!!) 将“falsy”转换为布尔值 false。

  • 这表明 9/31/2021 和 2/29/2021 是有效日期,但事实并非如此。 (4认同)
  • 罗基特说得好!Javascript Date 是宽松的,允许更高(或更低)的数字,并将更高的月份日期视为接下来的月份。因此,“2/29/2021”计算为 2021 年 3 月 1 日。我更新了该函数以消除此问题,它现在检查最小/最大范围,包括闰年。 (2认同)
  • 好的,但这仅适用于日期格式为 **mm/dd/yyyy** 的情况。如果它的格式为 **yyyy/dd/mm** 或 **yyyy/mm/dd** 那么这将返回 false。 (2认同)

Jin*_*Yao 15

我使用以下代码验证年,月和日期的值.

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;
}
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请参阅javascript中的检查日期


Yus*_*sef 14

你可以用这个scirpt检查txDate.value的有效格式.如果它的格式不正确,则Date obejct不实例化,并将null返回给dt.

 var dt = new Date(txtDate.value)
 if (isNaN(dt))
Run Code Online (Sandbox Code Playgroud)

正如@ MiF的建议简短

 if(isNaN(new Date(...)))
Run Code Online (Sandbox Code Playgroud)


Seb*_* H. 12

这里有太多复杂的答案,但一条简单的线就足够了(ES5):

Date.prototype.isValid = function (d) { return !isNaN(Date.parse(d)) } ;
Run Code Online (Sandbox Code Playgroud)

甚至在ES6中:

Date.prototype.isValid = d => !isNaN(Date.parse(d));
Run Code Online (Sandbox Code Playgroud)


Dmy*_*nko 9

好的解决方案 包含在我的辅助函数库中,现在看起来像这样:

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());
}
Run Code Online (Sandbox Code Playgroud)


Nic*_*ras 9

对于Angular.js项目,您可以使用:

angular.isDate(myDate);
Run Code Online (Sandbox Code Playgroud)

  • 当测试使用无效日期初始化的日期对象时,返回true. (3认同)

Car*_*ann 9

当人们离不开图书馆时,我很少推荐图书馆。但考虑到迄今为止的大量答案,似乎值得指出的是,流行的库“date-fns”有一个函数isValid。以下文档摘自他们的网站:

有效参数 v2.0.0之前 v2.0.0 及以上
新日期() 真的 真的
新日期('2016-01-01') 真的 真的
新日期('') 错误的 错误的
新日期(1488370835081) 真的 真的
新日期(NaN) 错误的 错误的
'2016-01-01' 类型错误 错误的
类型错误 错误的
1488370835081 类型错误 真的
类型错误 错误的


小智 8

这对我有用

new Date('foo') == 'Invalid Date'; //is true
Run Code Online (Sandbox Code Playgroud)

但是这没用

new Date('foo') === 'Invalid Date'; //is false
Run Code Online (Sandbox Code Playgroud)

  • 我相信这取决于浏览器. (5认同)
  • 如果要进行类型比较,请使用“.toString()”方法。`new Date('foo').toString() === 'Invalid Date'` 将返回 `true` (3认同)

Jas*_*lia 7

我看到了一些非常接近这个小片段的答案。

JavaScript方式:

function isValidDate(dateObject){ return new Date(dateObject).toString() !== 'Invalid Date'; }
isValidDate(new Date('WTH'));
Run Code Online (Sandbox Code Playgroud)

TypeScript方式:

const isValidDate = dateObject => new Date(dateObject ).toString() !== 'Invalid Date';
isValidDate(new Date('WTH'));
Run Code Online (Sandbox Code Playgroud)

  • 后者与 TypeScript *无关*。这是完全有效的 JS。 (8认同)
  • 不确定我是否遗漏了一些东西,但是两次执行 new Date() 是不是毫无意义? (2认同)
  • 传递 Date 构造函数可以转换为有效 Date 对象的任何值都将被视为有效日期,例如 `isValidDate(0)` 和 `isValidDate(['0'])` 返回 true。 (2认同)

Dex*_*Dex 6

在尝试验证日期(例如2/31/2012)时,这些答案都不适合我(在Safari 6.0中测试),但是,当尝试任何大于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
Run Code Online (Sandbox Code Playgroud)


saa*_*aaj 6

Date.prototype.toISOString抛出RangeError无效日期(至少在 Chromium 和 Firefox 中)。您可以将其用作验证手段,但可能不需要isValidDate这样(EAFP)。否则就是:

function isValidDate(d)
{
  try
  {
    d.toISOString();
    return true;
  }
  catch(ex)
  {
    return false;    
  }    
}
Run Code Online (Sandbox Code Playgroud)

  • 根据 ECMA-262 定义,它似乎是唯一抛出错误的函数。15.9.5.43 Date.prototype.toISOString ( ) 此函数返回一个 String 值,表示此 Date 对象所表示的时间实例。字符串的格式是15.9.1.15中定义的日期时间字符串格式。所有字段都存在于字符串中。时区始终为 UTC,由后缀 Z 表示。如果此对象的时间值不是有限数字,则会引发 RangeError 异常。 (2认同)

Joh*_*ohn 5

以上解决方案都没有为我工作,但是工作是什么

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);
    }
Run Code Online (Sandbox Code Playgroud)

上面的代码将看到JS何时将02/31/2012变为03/02/2012,它无效

  • 好的,但这会测试字符串是M/D/Y格式的日期,而不是"有效和无效日期对象之间的差异".这不是真正的问题. (3认同)

小智 5

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;
}
Run Code Online (Sandbox Code Playgroud)


And*_*iko 5

你可以尝试这样的事情:

const isDate = (val) => !isNaN(new Date(val).getTime());
Run Code Online (Sandbox Code Playgroud)