【问题标题】:How to check whether an object is a date?如何检查对象是否为日期?
【发布时间】:2010-10-13 05:28:16
【问题描述】:

我在网页上有一个烦人的错误:

date.GetMonth() 不是函数

所以,我想我做错了什么。变量date 不是Date 类型的对象。 如何在 Javascript 中检查数据类型?我尝试添加 if (date),但它不起作用。

function getFormatedDate(date) {
    if (date) {
       var month = date.GetMonth();
    }
}

那么,如果我想编写防御性代码并阻止日期(不是一个)被格式化,我该怎么做呢?

谢谢!

更新:我不想检查日期的格式,但我想确保传递给方法getFormatedDate() 的参数是Date 类型。

【问题讨论】:

标签: javascript date


【解决方案1】:

作为鸭子打字的替代方法

typeof date.getMonth === 'function'

您可以使用instanceof 运算符,即,但对于无效日期,它也会返回 true,例如new Date('random_string') 也是 Date 的实例

date instanceof Date

如果对象跨越帧边界,这将失败。

解决方法是通过检查对象的类

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

【讨论】:

  • 出于兴趣,您知道跨帧边界时失败的原因吗?
  • @Simon:JS 全局变量是当前全局对象的本地变量(又名 windowself);不同的框架有自己的全局对象,它们的属性(即全局)引用不同的对象: 框架1 中的Date 与框架2 中的Date 是不同的函数对象; Date.prototype 也是如此,这就是 instanceof 失败的原因:来自 frame1 的 Date.prototype 不是来自 frame2 的 Date 实例原型链的一部分
  • 克里斯托夫,你叫什么“框架”? IFRAME,FRAMESET 中的每一帧或其他东西(我的意思是 JS 特定的,而不是 HTML 的东西)?
  • new Date('something') instanceof Date 在 Chrome 中返回 true。那就不行了。
  • 检测日期类型对象(与普通对象或字符串相反)和验证您希望是日期的对象是两个不同的任务。在许多情况下,函数的输入可能是多种不同数据类型之一。就我而言,我可以相信我得到的任何 Date 对象都是有效的(它不是直接来自客户端)如果验证是一个问题,这里有一个包含多个选项的帖子。 stackoverflow.com/questions/1353684/…
【解决方案2】:

您可以使用以下代码:

(myvar instanceof Date) // returns true or false

【讨论】:

  • 为什么这不是被接受或更多赞成的答案?简单地检查日期是否具有 .getMonth 属性可能会触发误报。
  • instanceof 可能会触发误报,请参阅 Christoph 对他自己的回答的评论。
  • @doremi 下面是instanceof触发误报的演示:jsbin.com/vufufoq/edit?html,js,console
  • 因为这两种方法都有同样的缺陷。您必须在上面的辩论中使用@Jan 的方法来确保getMonth() 不会在其误报实例上返回 NaN,至少使用instanceof Date 至少看起来部分。
【解决方案3】:

为了检查该值是否是标准 JS-date 对象的有效类型,您可以使用这个谓词:

function isValidDate(date) {
  return date && Object.prototype.toString.call(date) === "[object Date]" && !isNaN(date);
}
  1. date 检查参数是否不是falsy valueundefinednull0"" 等)
  2. Object.prototype.toString.call(date) 返回给定对象类型的native string representation - 在我们的例子中是"[object Date]"。因为date.toString() overrides its parent method,我们需要.call.apply直接来自Object.prototype的方法哪个..
  3. !isNaN(date) 最后检查该值是否不是Invalid Date

【讨论】:

  • isNaN 可用于检查 Date。那是某种 PHP 级别的愚蠢。
  • @Nick 日期是一个数字。
  • @Josiah 好吧,当然,删除所有上下文,那里有一个时间戳:typeof Date.now() === "number",但是:typeof new Date() === "object"。不过,更现实地说,日期是时间和空间中的位置。
  • 这在高度不稳定的环境中对我有用,在这种环境中可能存在字符串值的所有可能性(实际日期、随机字母、空白、随机字符等)。
【解决方案4】:

函数是getMonth(),而不是GetMonth()

无论如何,您可以通过执行此操作来检查对象是否具有 getMonth 属性。这并不一定意味着该对象是一个 Date,只是任何具有 getMonth 属性的对象。

if (date.getMonth) {
    var month = date.getMonth();
}

【讨论】:

  • 检查是否可以调用:if (date.getMonth && typeof date.getMonth === "function") {...}
【解决方案5】:

如上所述,在使用之前检查函数是否存在可能是最简单的。如果你真的关心它是一个Date,而不仅仅是一个带有getMonth() 函数的对象,试试这个:

function isValidDate(value) {
    var dateWrapper = new Date(value);
    return !isNaN(dateWrapper.getDate());
}

如果它是Date,这将创建一个值的克隆,或者创建一个无效的日期。然后您可以检查新日期的值是否无效。

【讨论】:

  • 这对我有用,谢谢。但是,如果您传递一个数字,例如 0 或 1,它会将其视为有效日期......有什么想法吗?
  • 没错,@RicardoSanchez。如果您可能会得到数字,您可能想使用已接受的答案 (Object.prototype.toString.call(value) === '[object Date]')。这个答案中的方法真的告诉你value是否可以转换为Date
【解决方案6】:

对于所有类型,我都制作了一个 Object 原型函数。可能对你有用

Object.prototype.typof = function(chkType){
      var inp        = String(this.constructor),
          customObj  = (inp.split(/\({1}/))[0].replace(/^\n/,'').substr(9),
          regularObj = Object.prototype.toString.apply(this),
          thisType   = regularObj.toLowerCase()
                        .match(new RegExp(customObj.toLowerCase()))
                       ? regularObj : '[object '+customObj+']';
     return chkType
            ? thisType.toLowerCase().match(chkType.toLowerCase()) 
               ? true : false
            : thisType;
}

现在您可以像这样检查 any 类型:

var myDate     = new Date().toString(),
    myRealDate = new Date();
if (myRealDate.typof('Date')) { /* do things */ }
alert( myDate.typof() ); //=> String

[2013 年 3 月编辑] 基于不断深入的洞察,这是一种更好的方法:

Object.prototype.is = function() {
        var test = arguments.length ? [].slice.call(arguments) : null
           ,self = this.constructor;
        return test ? !!(test.filter(function(a){return a === self}).length)
               : (this.constructor.name ||
                  (String(self).match ( /^function\s*([^\s(]+)/im)
                    || [0,'ANONYMOUS_CONSTRUCTOR']) [1] );
}
// usage
var Some = function(){ /* ... */}
   ,Other = function(){ /* ... */}
   ,some = new Some;
2..is(String,Function,RegExp);        //=> false
2..is(String,Function,Number,RegExp); //=> true
'hello'.is(String);                   //=> true
'hello'.is();                         //-> String
/[a-z]/i.is();                        //-> RegExp
some.is();                            //=> 'ANONYMOUS_CONSTRUCTOR'
some.is(Other);                       //=> false
some.is(Some);                        //=> true
// note: you can't use this for NaN (NaN === Number)
(+'ab2').is(Number);                 //=> true

【讨论】:

    【解决方案7】:

    如果您不关心 iframe/其他上下文,这是一种非常简单的方法。

    // Invalid Date.getTime() will produce NaN
    if (date instanceof Date && date.getTime()) {
        console.log("is date!");
    }
    
    • 检查对象是否实际上是Date 而不是看起来像的东西。任何对象都可以有一个getMonth 函数。
    • 确保日期不是Invalid Date
    • 不会将值传递给new Date(),在该new Date() 可以将数字甚至字符串转换为日期。

    如果您需要支持 iframe 和不同的上下文,您可以使用接受的答案,但添加额外的检查以识别无效日期。

    // Invalid Date.getTime() will produce NaN
    if (Object.prototype.toString.call(date) === '[object Date]' && date.getTime()) {
        console.log("is date!");
    }
    
    

    【讨论】:

      【解决方案8】:

      我发现的最好方法是:

      !isNaN(Date.parse("some date test"))
      //
      !isNaN(Date.parse("22/05/2001"))  // true
      !isNaN(Date.parse("blabla"))  // false
      

      【讨论】:

      • 这不起作用。你的真实路线实际上是错误的,问题是关于检查一个对象是否是一个日期对象......
      • @jspassov 的答案对于字符串是否为日期更准确。我一直在寻找的。谢谢!!
      • 这是简单检查字符串是否为日期的最佳答案
      • 这不适用于带数字的字符串(例如 -:测试 1)
      • 是的,这样您的系统将 1 作为 YEAR 并且 0001 年 1 月 01 日的日期确实是日期 :-)
      【解决方案9】:

      UnderscoreJSLodash 有一个名为 .isDate() 的函数,这似乎正是您所需要的。值得看看它们各自的实现:Lodash isDate, UnderscoreJs

      【讨论】:

        【解决方案10】:

        您可以使用以下解决方法,而不是所有解决方法:

        dateVariable = new Date(date);
        if (dateVariable == 'Invalid Date') console.log('Invalid Date!');
        

        我发现这个 hack 更好!

        【讨论】:

        • 这不起作用,除非你把toString()放在dateVariable之后,因为无效日期不会返回字符串
        【解决方案11】:

        我一直在使用一种更简单的方法,但不确定这是否仅在 ES6 中可用。

        let a = {name: "a", age: 1, date: new Date("1/2/2017"), arr: [], obj: {} };
        console.log(a.name.constructor.name); // "String"
        console.log(a.age.constructor.name);  // "Number"
        console.log(a.date.constructor.name); // "Date"
        console.log(a.arr.constructor.name);  // "Array"
        console.log(a.obj.constructor.name);  // "Object"
        

        但是,这不适用于 null 或 undefined,因为它们没有构造函数。

        【讨论】:

        • 任何具有构造函数名称“Date”的自定义对象也会返回"Date",这与检查参数是否具有getMonth 属性一样危险。
        • @boghyon 听起来好像无论谁使用已经预定义的 Javascript 标准库的构造函数名称创建对象,都没有首先遵循最佳实践。这就像下载 lodash 然后创建您自己的 lodash 模块并期望一切正常。
        • 请注意,如果值为null,则value.constructor.name 会抛出异常。
        【解决方案12】:

        您可以检查是否存在特定于 Date 对象的函数:

        function getFormatedDate(date) {
            if (date.getMonth) {
                var month = date.getMonth();
            }
        }
        

        【讨论】:

          【解决方案13】:

          你也可以使用简写形式

          function getClass(obj) {
            return {}.toString.call(obj).slice(8, -1);
          }
          alert( getClass(new Date) ); //Date
          

          或类似的东西:

          (toString.call(date)) == 'Date'
          

          【讨论】:

            【解决方案14】:

            如果是日期,这个函数将返回true,否则返回false

            function isDate(myDate) {
                return myDate.constructor.toString().indexOf("Date") > -1;
            } 
            

            【讨论】:

            • isDate(new (function AnythingButNotDate(){ })()) 返回true
            【解决方案15】:

            还有一个变种:

            Date.prototype.isPrototypeOf(myDateObject)
            

            【讨论】:

            • 又好又短!但不幸的是,它有same issue as instanceof
            • @BoghyonHoffmann 在 iF​​rame 的情况下可能看起来像:iWindow.Date.prototype.isPrototypeOf(iWindow.date); // true iWindow.date instanceof iWindow.Date; // true
            【解决方案16】:

            通过以下方法,您甚至可以检查日期为“无效日期”

            if(!!date.getDate()){
                console.log('date is valid')
            }
            

            【讨论】:

              【解决方案17】:

              使用 try/catch 的方法

              function getFormattedDate(date = new Date()) {
                try {
                  date.toISOString();
                } catch (e) {
                  date = new Date();
                }
                return date;
              }
              
              console.log(getFormattedDate());
              console.log(getFormattedDate('AAAA'));
              console.log(getFormattedDate(new Date('AAAA')));
              console.log(getFormattedDate(new Date(2018, 2, 10)));

              【讨论】:

                【解决方案18】:

                箭头函数

                const isValidDate = (value: any) => value instanceof Date && !isNaN(value);
                

                功能:

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

                【讨论】:

                  【解决方案19】:

                  实际上日期的类型是Object。但是您可以检查该对象是否具有getMonth 方法以及它是否可调用。

                  function getFormatedDate(date) {
                      if (date && date.getMonth && date.getMonth.call) {
                         var month = date.getMonth();
                      }
                  }
                  

                  【讨论】:

                  • 克里斯托夫的回答更准确。拥有“调用”属性并不一定意味着它是一个函数!
                  【解决方案20】:

                  this answer 启发,此解决方案适用于我的情况(我需要检查从 API 收到的值是否为日期):

                  !isNaN(Date.parse(new Date(YourVariable)))
                  

                  这样,如果是来自客户端的随机字符串,或者任何其他对象,你可以找出它是否是一个类似日期的对象。

                  【讨论】:

                  • 这对我来说很完美。谢谢。
                  【解决方案21】:

                  我在使用 React 钩子时遇到了一些问题,其中 Date 稍后会进入/延迟加载,然后初始状态不能为 null,它不会通过 ts 检查,但显然一个空的 Object 可以解决问题! :)

                  const [birthDate, setBirthDate] = React.useState({})
                  
                  <input
                    value={birthDate instanceof Date ? birthDate.toISOString() : ''}
                    name="birthDay"
                  />
                  

                  【讨论】:

                    【解决方案22】:

                    我们也可以通过下面的代码来验证

                    var a = new Date();
                    a.constructor === Date
                    /*
                    true
                    */
                    

                    【讨论】:

                    • function Date() {/*...*/}的构造函数也是Date。 IE。简单地比较构造函数太容易出错,这通常会导致误报。使用 stackoverflow.com/a/44198641/5846045 绕过用户定义的对象类型
                    【解决方案23】:

                    如果您使用的是 Typescript,您可以使用 Date 类型进行检查:

                    const formatDate( date: Date ) => {}
                    

                    【讨论】:

                      【解决方案24】:

                      你就不能用

                      function getFormatedDate(date) {
                          if (date.isValid()) {
                             var month = date.GetMonth();
                          }
                      }
                      

                      【讨论】:

                      • 不,只有日期对象有isValid方法
                      • @grumpy @nikkwong 没有也没有。标准日期对象没有isValid。只有moment.js 有这样的API。
                      • isValid 方法在日期对象中不可用,因此会引发错误。
                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 2020-07-03
                      • 1970-01-01
                      • 1970-01-01
                      • 2013-08-25
                      • 2013-10-31
                      • 2013-12-23
                      相关资源
                      最近更新 更多