题 在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的解决方案可以做到这一点,但我需要跨浏览器进行测试。我也想知道是否有更优雅的方式。
  • Ash让我考虑不接受我的API接受 Date 实例,这将是最容易验证。
  • Borgar建议测试一个 Date 实例,然后测试 Date的时间价值。如果日期无效,则时间值为 NaN。我查了一下 ECMA-262 这个行为是标准的,这正是我正在寻找的。

1085
2017-08-30 11:34


起源


您可以通过将函数体更改为:来删除if语句: return ( Object.prototype.toString.call(d) === "[object Date]" && !isNaN(d.getTime()) ); - styfle
@styfle - 猜测它是一种样式偏好:我发现将类型检查与等式逻辑分开更清楚。 - orip
@orip话语正是在问题中非常沮丧的。 请参阅相关的元主题以了解其背后的基本原理。 在问题本身中回答自己的问题是违反网站政策的。 OTOH,感谢您的回答,并在您的答案中“编辑”是典型的绒毛。如果你想要一个最受好评的问题来确定你是一个不知道SO是什么以及如何使用它的人,并且不希望得知 - 作为我的客人。 - vaxquis
@orip:它没有“丢失”;如果你想再次看到它,它仍然会混淆问题的修订历史。但它不属于一个问题。在37k代表你应该知道这一点。 - Lightness Races in Orbit
请停止编辑战争。讨论了关于这个问题的编辑 元。请不要进一步编辑/回滚此帖子。如果您不同意以前的编辑/回滚或对它们有任何意见,请在该元线程上发布,而不是在此处。 - Lundin


答案:


这是我将如何做到这一点:

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]:如果您不关心来自其他JS上下文(外部窗口,框架或iframe)的Date对象,则可以首选这种更简单的形式:

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

890
2017-08-30 11:48



为什么不首先进行第一次比较的“d instanceof Date”? - Chris Charabaruk
克里斯:“d instance Date”也适用于无效日期 - orip
instanceof在帧之间中断。鸭子打字也可以正常工作:validDate == d && d.getTime &&!isNaN(d.getTime()); - 由于问题是一般的效用函数,我更喜欢更严格。 - Borgar
@Borgar,刚刚找到我的答案:“在多帧DOM环境中编写脚本问题时出现问题。简而言之,在一个iframe中创建的Array对象不与另一个iframe中创建的数组共享[[Prototype]]它们的构造函数是不同的对象,因此instanceof和构造函数检查都失败了。“ - Ash
你根本不需要 d.getTime 只是 isNan(d) - TecHunter


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

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

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

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


213
2017-08-30 11:47



+1,非常好,谢谢! Date.parse返回毫秒,而不是Date对象,因此在测试之后我们仍然需要从它构造一个Date对象(new Date(d)) - orip
很高兴能提供帮助,我编写了答案,以便更清楚地表明Date.parse返回的时间戳以毫秒为单位。 - Ash
-1 Dunno为什么这么多的选票, Date.parse 是依赖于实现的,并且绝对不能信任解析通用日期字符串。在流行的浏览器中没有正确解析的单一格式,更不用说所有使用的格式(尽管最终是ISO8601格式) 在ES5中指定 应该可以)。 - RobG
这可能会有效,但仍然会返回“02/31/2012”的误报,这是无效的 - John
Date.parse的行为在浏览器中不是标准的 - Genady Sergeev


你可以检查一下的有效性 Date 目的 d 通过

d instanceof Date && isFinite(d)

为避免跨框架问题,可以替换 instanceof 检查

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

打电话给 getTime() 如在 Borgar的回答 是不必要的 isNaN() 和 isFinite() 两者都隐式转换为数字。


88
2017-08-30 14:07



在chrome中尝试这个 - Object.prototype.toString.call(new Date(“2013-07-09T19:07:9Z”))。它将返回“[object Date]”。据你所知,“2013-07-09T19:07:9Z”应该是一个有效的日期。但事实并非如此。您可以通过执行var dateStr = new Date(“2013-07-09T19:07:9Z”)再次在chrome中验证它; dateStr它将返回无效日期。 - Tintin
@Tintin:那是什么 isFinite() 适用于 - toString.call() 只是替代了 instanceof 部分检查 - Christoph
与'[object Date]'进行比较是否适用于非英语浏览器?我对此表示怀疑。 - kristianp
@kristianp实际上它可能会甚至可能是ECMAScript规范的一部分。但是,是的,它看起来很难看。 - binki
对我来说,这里的第一种方法是最好的选择,虽然我不确定使用是否有任何现实世界的优势 isFinite 过度 isNaN (两者都很好用 Date(Infinity))。此外,如果你想要相反的条件,它会变得更简单: if (!(date instanceof Date) || isNaN(date))。 - Andrew


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

履行

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

66
2017-09-11 15:03



isNaN 是一种更明确的测试NaN的方法 - orip
然而,你总是找人写自己的版本:) documentcloud.github.com/underscore/docs/... - Ash Clarke
因为我尊重underscore.js这引发了一些研究。 isNaN("a") === true,而 ("a" !== "a") === false。值得思考。 +1 - orip
我测试了我在这里找到的3个主要解决方案的性能。恭喜,你是赢家! jsperf.com/detecting-an-invalid-date - zVictor
@Ali这是一个有效的日期对象。 new Date("02-31-2000") // Thu Mar 02 2000 00:00:00 GMT+0000 (GMT Standard Time)。如果要将字符串传递给日期构造函数,则必须传入标准化字符串以获得可靠的结果。具体来说,“字符串应采用Date.parse()方法识别的格式”。 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/... - Ash Clarke


检查有效日期的最短答案

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

49
2017-07-04 10:10



这非常适合我想要的东西。谢谢! - Fred
最佳答案。其他一切都过于复杂或不准确。 - Polyducks
唯一的问题是如果日期不是Date类型;你得到一个JS错误。 - Andrew
@Andrew您需要创建日期对象,如果您已有对象,则使用 date && !isNaN(date.getTime()) - abhirathore2006
对,就像8年前的其他答案一样。 :P stackoverflow.com/a/1353945/2321042 - Andrew


你可以简单地使用 moment.js

这是一个例子:

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

验证部分 在文档中很清楚。

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

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

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


35
2017-10-14 20:18



最好的解决方案,非常容易实现,适用于任何格式(我的情况是dd / MM / yyyy),也知道闰年并且不会将无效日期(即29/02/2015)转换为有效日期(即30/03/2015)。要检查formad dd / MM / yyyy中的日期,我只需要使用 moment("11/06/1986", "DD/MM/YYYY").isValid(); - Rafael Merlin
这个Moment的使用已被弃用:( - James Sumners
@JamesSumners怎么样/为什么? - binki
此用途尚未折旧。不使用格式字符串的调用时刻(输入)将被折旧(除非输入是ISO格式的)。 - Chet
处理许多日期时,此方法可能非常慢。在这些情况下最好使用正则表达式。 - Grid Trekkor


想提一下,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.';
}

(更多信息请参阅指定日期格式 http://api.jqueryui.com/datepicker/#utility-parseDate

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

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


35
2018-02-15 19:30



Upvote是第一个使用非英语/语言环境日期格式的答案。 - ax.