在javascript中检测”无效日期”日期实例

Detecting an “invalid date” Date instance in JavaScript

我想知道JS中的有效日期对象和无效日期对象之间的区别,但不知道如何:

1
2
3
4
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函数有什么想法吗?

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


我可以这样做:

1
2
3
4
5
6
7
8
9
10
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上下文(外部窗口、框架或iframes)的日期对象,可以使用此简单形式:

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


不使用new Date(),应使用:

1
2
3
4
5
var timestamp = Date.parse('foo');

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

Date.parse()返回一个时间戳,一个表示1970年1月1日以来毫秒数的整数。如果无法解析提供的日期字符串,则返回NaN


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

1
d instanceof Date && isFinite(d)

为了避免交叉帧问题,可以用

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

由于isNaN()isFinite()都隐式转换为数字,因此不需要像borgar的答案中那样调用getTime()


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

实施

1
2
3
4
5
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();
};

用法

1
2
3
4
5
6
7
var d = new Date("lol");

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

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

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


检查有效日期的最短答案

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


您只需使用moment.js

下面是一个例子:

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

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

此外,以下分析标志导致日期无效:

  • overflow:日期字段溢出,如13个月、32个月(或非闰年的2月29日)、367天等。溢出包含要匹配无效单元的索引;1表示没有溢出。
  • invalidMonth:无效的月份名称,如moment(‘marbruary’,‘mmmm’)。包含无效的月份字符串本身,否则为空。
  • empty:不包含可分析内容的输入字符串,如moment(‘这是胡说’);。布尔函数。
  • 等。

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


请注意,jquery ui datepicker小部件有一个非常好的日期验证器实用方法,用于检查格式和有效性(例如,不允许01/33/2013日期)。

即使您不想将页面上的datepicker小部件用作UI元素,也可以始终将其.js库添加到页面中,然后调用validator方法,将要验证的值传递给它。为了让生活更简单,它需要一个字符串作为输入,而不是一个javascript日期对象。

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

它没有被列为一个方法,但它确实存在——作为一个实用函数。在页面中搜索"parsedate",您会发现:

$.datepicker.parseDate(格式、值、设置)-从具有指定格式的字符串值中提取日期。

示例用法:

1
2
3
4
5
6
7
8
9
10
11
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/实用程序parsedate)

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

如果成功分析传入的字符串值,"testdate"的值将是表示传入字符串值的javascript日期对象。如果没有,它将是未定义的。


我真的很喜欢克里斯托夫的方法(但没有足够的声誉投票支持)。对于我的使用,我知道我总是有一个日期对象,所以我只是用一个有效的()方法扩展了日期。

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

现在我可以写这个了,它比检查代码中的有限性更具描述性…

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


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


我使用以下代码来验证年、月和日期的值。

1
2
3
4
5
6
7
8
9
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中的检查日期。


这里已经有太多复杂的答案,但一句简单的话就足够了(es5):

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

甚至在ES6中:

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


您可以使用此scirpt检查txtdate.value的有效格式。如果格式不正确,则不实例化日期obejct,并将空值返回到dt。

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

正如@mif在短期内建议的那样

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


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

1
angular.isDate(myDate);


不错的解决方案!包括在我的辅助功能库中,现在看起来如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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());
}


这对我有效

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

但是这不起作用

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


当我试图验证一个日期(如2012年2月31日)时,这些答案都不起作用(在Safari 6.0中进行了测试),但是,当尝试任何超过31日的日期时,它们都会起作用。

所以我不得不稍微用力一点。假设日期的格式为mm/dd/yyyy。我正在使用@blowx答案:

1
2
3
4
5
6
7
8
9
10
11
12
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


1
2
3
4
5
6
7
8
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;
}


上述解决方案对我来说都不起作用,但真正起作用的是

1
2
3
4
5
6
7
8
9
10
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将2012年2月31日改为2012年2月3日时看到其无效。


我已经编写了这个函数。将一个字符串参数传递给它,它将根据"dd/mm/yyyy"格式确定它是否为有效日期。

这是一个测试

输入:"哈哈哈",输出:假。

输入:"29/2/2000",输出:真。

输入:"29/2/2001",输出:假。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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;
    }
}


我结合了我在检查给定对象是否满足以下条件时发现的最佳性能结果:

  • 是日期实例(此处为基准)
  • 有有效日期(此处为基准)

结果如下:

1
2
3
4
5
6
7
function isValidDate(input) {
  if(!(input && input.getTimezoneOffset && input.setUTCFullYear))
    return false;

  var time = input.getTime();
  return time === time;
};

受Borgar方法的启发,我确保代码不仅验证日期,而且实际上确保日期是真实日期,这意味着不允许像2011年9月31日和2011年2月29日这样的日期。

1
2
3
4
5
6
7
8
9
10
11
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!";
}


日期对象到字符串是检测两个字段是否都是有效日期的更简单可靠的方法。例如,如果您在日期输入字段中输入"------"。上面的一些答案是行不通的。

1
2
3
4
5
6
7
8
9
10
11
12
jQuery.validator.addMethod("greaterThan",

    function(value, element, params) {
        var startDate = new Date($(params).val());
        var endDate = new Date(value);

        if(startDate.toString() === 'Invalid Date' || endDate.toString() === 'Invalid Date') {
            return false;
        } else {
            return endDate > startDate;
        }
    },'Must be greater than {0}.');

1
2
3
4
5
6
7
function isValidDate(strDate) {
    var myDateStr= new Date(strDate);
    if( ! isNaN ( myDateStr.getMonth() ) ) {
       return true;
    }
    return false;
}

像这样称呼它

1
2
isValidDate(""2015/5/2""); // => true
isValidDate(""2015/5/2a""); // => false

您可以将日期和时间转换为gettime()的毫秒数。

getTime()方法在无效时不返回数字NaN

1
2
3
if(!isNaN(new Date("2012/25/255").getTime()))
  return 'valid date time';
  return 'Not a valid date time';


选定的答案很好,我也在使用它。但是,如果您正在寻找一种验证用户日期输入的方法,那么您应该知道,日期对象对于将看似无效的构造参数转换为有效的构造参数非常持久。以下单元测试代码说明了这一点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
QUnit.test("valid date test", function( assert ) {
  //The following are counter-examples showing how the Date object will
  //wrangle several 'bad' dates into a valid date anyway
  assert.equal(isValidDate(new Date(1980, 12, 15)), true);
  d = new Date();
  d.setFullYear(1980);
  d.setMonth(1);
  d.setDate(33);
  assert.equal(isValidDate(d), true);
  assert.equal(isValidDate(new Date(1980, 100, 150)), true);
  //If you go to this exterme, then the checker will fail
  assert.equal(isValidDate(new Date("This is junk")), false);
  //This is a valid date string
  assert.equal(isValidDate(new Date("November 17, 1989")), true);
  //but is this?
  assert.equal(isValidDate(new Date("November 35, 1989")), false);  
  //Ha!  It's not.  So, the secret to working with this version of
  //isValidDate is to pass in dates as text strings... Hooboy
  //alert(d.toString());
});

基于最高评价答案的就绪功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
  /**
   * 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;
}

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

JavaScript方式:

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

打字方式:

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

Date.prototype.toISOString在无效日期抛出RangeError(至少在chromium和firefox中)。您可以将其用作一种验证方法,并且可能不需要isValidDate(EAFP)。否则就是:

1
2
3
4
5
6
7
8
9
10
11
12
function isValidDate(d)
{
  try
  {
    d.toISOString();
    return true;
  }
  catch(ex)
  {
    return false;    
  }    
}


一般来说,无论什么日期植入在浏览器堆栈中,我都会坚持。这意味着在这个回复的日期之后,在chrome、firefox和safari中调用todatestring()时,总是会得到"无效日期"。

1
2
3
4
5
if(!Date.prototype.isValidDate){
  Date.prototype.isValidDate = function(){
    return this.toDateString().toLowerCase().lastIndexOf('invalid') == -1;
  };
}

但我没有在IE中测试这个。


1
2
3
function isValidDate(date) {
  return !! (Object.prototype.toString.call(date) ==="[object Date]" && +date);
}


对于日期的基于int 1的组件:

1
2
3
4
var is_valid_date = function(year, month, day) {
    var d = new Date(year, month - 1, day);
    return d.getFullYear() === year && (d.getMonth() + 1) === month && d.getDate() === day
};

测验:

1
2
3
4
5
    is_valid_date(2013, 02, 28)
&&  is_valid_date(2016, 02, 29)
&& !is_valid_date(2013, 02, 29)
&& !is_valid_date(0000, 00, 00)
&& !is_valid_date(2013, 14, 01)

所以我喜欢@ask clarke answer,只需稍加改进,为无法通过var d=new date(d)的日期添加try catch块-

1
2
3
4
5
6
7
8
9
function checkIfDateNotValid(d) {
        try{
            var d = new Date(d);
            return !(d.getTime() === d.getTime()); //NAN is the only type which is not equal to itself.
        }catch (e){
            return true;
        }

    }


我认为这其中有些是一个漫长的过程。我们可以将其缩短如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 function isValidDate(dateString) {
        debugger;
        var dateStringSplit;
        var formatDate;

        if (dateString.length >= 8 && dateString.length<=10) {
            try {
                dateStringSplit = dateString.split('/');
                var date = new Date();
                date.setYear(parseInt(dateStringSplit[2]), 10);
                date.setMonth(parseInt(dateStringSplit[0], 10) - 1);
                date.setDate(parseInt(dateStringSplit[1], 10));

                if (date.getYear() == parseInt(dateStringSplit[2],10) && date.getMonth()+1 == parseInt(dateStringSplit[0],10) && date.getDate() == parseInt(dateStringSplit[1],10)) {
                    return true;
                }
                else {
                    return false;
                }

            } catch (e) {
                return false;
            }
        }
        return false;
    }


只需要date.parse(valueToBeTested) > 0。一个有效日期将返回epoch值,一个无效值将返回NaN,由于它不是数字,因此无法通过> 0测试。

这是如此简单,一个助手函数将不会保存代码,尽管它可能更易于阅读。如果你想要一个:

1
2
3
String.prototype.isDate = function() {
  return !Number.isNaN(Date.parse(this));
}

使用:

1
"StringToTest".isDate();


1
2
3
4
5
6
7
8
9
10
11
12
13
14
var isDate_ = function(input) {
        var status = false;
        if (!input || input.length <= 0) {
          status = false;
        } else {
          var result = new Date(input);
          if (result == 'Invalid Date') {
            status = false;
          } else {
            status = true;
          }
        }
        return status;
      }

这种风格的isvalidate使用处理闰年的正则表达式:

1
2
3
4
function isValidDate(value)
{
    return /((^(10|12|0?[13578])([/])(3[01]|[12][0-9]|0?[1-9])([/])((1[8-9]\d{2})|([2-9]\d{3}))$)|(^(11|0?[469])([/])(30|[12][0-9]|0?[1-9])([/])((1[8-9]\d{2})|([2-9]\d{3}))$)|(^(0?2)([/])(2[0-8]|1[0-9]|0?[1-9])([/])((1[8-9]\d{2})|([2-9]\d{3}))$)|(^(0?2)([/])(29)([/])([2468][048]00)$)|(^(0?2)([/])(29)([/])([3579][26]00)$)|(^(0?2)([/])(29)([/])([1][89][0][48])$)|(^(0?2)([/])(29)([/])([2-9][0-9][0][48])$)|(^(0?2)([/])(29)([/])([1][89][2468][048])$)|(^(0?2)([/])(29)([/])([2-9][0-9][2468][048])$)|(^(0?2)([/])(29)([/])([1][89][13579][26])$)|(^(0?2)([/])(29)([/])([2-9][0-9][13579][26])$))/.test(value)
}

此函数用于验证由字符分隔的数字格式的字符串日期,例如dd/mm/yyyy、mm/dd/yyyy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/*
Param  :
1)the date in string data type
2)[optional - string - default is"/"] the date delimiter, most likely"/" or"-"
3)[optional - int - default is 0] the position of the day component when the date string is broken up via the String.split function (into arrays)
4)[optional - int - default is 1] the position of the month component when the date string is broken up via the String.split function (into arrays)
5)[optional - int - default is 2] the position of the year component when the date string is broken up via the String.split function (into arrays)

Return : a javascript date is returned if the params are OK else null
*/

function IsValidDate(strDate, strDelimiter, iDayPosInArray, iMonthPosInArray, iYearPosInArray) {
    var strDateArr; //a string array to hold constituents day, month, and year components
    var dtDate; //our internal converted date
    var iDay, iMonth, iYear;


    //sanity check
    //no integer checks are performed on day, month, and year tokens as parsing them below will result in NaN if they're invalid
    if (null == strDate || typeof strDate !="string")
        return null;

    //defaults
    strDelimiter = strDelimiter ||"/";
    iDayPosInArray = undefined == iDayPosInArray ? 0 : iDayPosInArray;
    iMonthPosInArray = undefined == iMonthPosInArray ? 1 : iMonthPosInArray;
    iYearPosInArray = undefined == iYearPosInArray ? 2 : iYearPosInArray;

    strDateArr = strDate.split(strDelimiter);

    iDay = parseInt(strDateArr[iDayPosInArray],10);
    iMonth = parseInt(strDateArr[iMonthPosInArray],10) - 1; // Note: months are 0-based
    iYear = parseInt(strDateArr[iYearPosInArray],10);

    dtDate = new Date(
        iYear,
        iMonth, // Note: months are 0-based
        iDay);

    return (!isNaN(dtDate) && dtDate.getFullYear() == iYear && dtDate.getMonth() == iMonth && dtDate.getDate() == iDay) ? dtDate : null; // Note: months are 0-based
}

示例调用:

1
2
3
4
5
6
var strDate="18-01-1971";

if (null == IsValidDate(strDate)) {

  alert("invalid date");
}

Yet another way to check whether the date is a valid date object:

1
2
3
4
const isValidDate = (date) =>
  typeof date === 'object' &&
  typeof date.getTime === 'function' &&
  !isNaN(date.getTime())

1
2
3
4
Date.valid = function(str){
  var d = new Date(str);
  return (Object.prototype.toString.call(d) ==="[object Date]" && !isNaN(d.getTime()));
}

https://gist.github.com/dustinpoisant/b83750d8671f10c414b346b16e290ecf