【问题标题】:Check if a string is a date value检查字符串是否为日期值
【发布时间】:2011-11-18 16:59:41
【问题描述】:

什么是检查值是否为有效日期的简单方法,允许任何已知的日期格式。

例如,我的值 10-11-200910/11/20092009-11-10T07:00:00+0000 都应该被识别为日期值,而值 20010350 则不应被识别为日期值。如果可能的话,最简单的检查方法是什么?因为时间戳也是允许的。

【问题讨论】:

    标签: javascript date-format


    【解决方案1】:

    2015 年更新

    这是一个老问题,但还有其他新问题,例如:

    作为这个副本的副本被关闭,所以我认为在这里添加一些新信息很重要。我写它是因为我害怕人们实际上复制并粘贴了此处发布的一些代码并在生产中使用它。

    这里的大多数答案 要么 使用了一些复杂的正则表达式,它们只匹配一些非常特定的格式并且实际上做错了(比如匹配 1 月 32 日,但不匹配广告中的实际 ISO 日期 - 请参阅 @987654322 @) 他们尝试将任何内容传递给Date 构造函数,并希望一切顺利。

    使用时刻

    正如我在this answer 中解释的那样,目前有一个可用的库: Moment.js

    它是一个在 JavaScript 中解析、验证、操作和显示日期的库,它具有比标准 JavaScript 日期处理函数更丰富的 API。

    它是 12kB 的压缩/gzip 文件,可以在 Node.js 和其他地方工作:

    bower install moment --save # bower
    npm install moment --save   # npm
    Install-Package Moment.js   # NuGet
    spm install moment --save   # spm
    meteor add momentjs:moment  # meteor
    

    使用 Moment,您可以非常具体地检查有效日期。有时添加一些有关您期望的格式的线索非常重要。例如,2015 年 6 月 22 日这样的日期看起来像是一个有效的日期,除非您使用 DD/MM/YYYY 格式,在这种情况下,该日期应被视为无效而被拒绝。有几种方法可以告诉 Moment 您期望什么格式,例如:

    moment("06/22/2015", "MM/DD/YYYY", true).isValid(); // true
    moment("06/22/2015", "DD/MM/YYYY", true).isValid(); // false
    

    true 参数在那里,因此如果输入不完全符合提供的格式之一(它在我看来应该是默认行为)。

    您可以使用内部提供的格式:

    moment("2015-06-22T13:17:21+0000", moment.ISO_8601, true).isValid(); // true
    

    而且你可以使用多种格式作为数组:

    var formats = [
        moment.ISO_8601,
        "MM/DD/YYYY  :)  HH*mm*ss"
    ];
    moment("2015-06-22T13:17:21+0000", formats, true).isValid(); // true
    moment("06/22/2015  :)  13*17*21", formats, true).isValid(); // true
    moment("06/22/2015  :(  13*17*21", formats, true).isValid(); // false
    

    请参阅:DEMO

    其他库

    如果你不想使用 Moment.js,还有其他库:

    2016 年更新

    我创建了 immoment 模块,它类似于 Moment(的子集),但不会因现有对象的突变而引起意外(有关更多信息,请参阅 the docs)。

    2018 年更新

    今天我建议使用Luxon 来进行日期/时间操作,而不是 Moment,它(与 Moment 不同)使所有对象都不可变,因此不会出现与日期的隐式突变相关的令人讨厌的意外。

    更多信息

    另见:

    Rob Gravelle 关于 JavaScript 日期解析库的系列文章:

    底线

    当然,任何人都可以尝试重新发明轮子,编写正则表达式(但在这样做之前实际阅读 ISO 8601 和 RFC 3339)或使用随机数据调用内置构造函数进行解析'Invalid Date' 之类的错误消息(您确定此消息在所有平台上完全相同吗?在所有语言环境中?将来?)您可以使用经过测试的解决方案并利用你的时间来改进它,而不是重新发明它。此处列出的所有库都是开源的免费软件。

    【讨论】:

    • 究竟应该如何使用它? moment("whatever 123").isValid() 返回true
    • @krivar 最好像这样使用它:moment("06/22/2015", "DD/MM/YYYY", true).isValid(); 明确提供预期的日期格式,并带有参数true 表示严格检查。我用更多信息和更好的例子更新了我的答案。
    • 虽然一样,但我正在验证用户输入,但我不知道预期的日期格式...
    • @JanVanderHaegen 如果可以假设 3/4/5 是有效日期,2015 年 4 月 1 日也是如此,那么我建议将这些格式(可能更多)添加到支持的明确列表中格式。请注意,您提到的 3/4/5 在没有明确格式的情况下是模棱两可的。
    • 这可能是我在 SO 上看到的最好和维护得最好的答案
    【解决方案2】:

    这就是我在我正在开发的应用程序中解决这个问题的方法:

    根据 krillgar 的反馈进行了更新:

    var isDate = function(date) {
        return (new Date(date) !== "Invalid Date") && !isNaN(new Date(date));
    }
    

    【讨论】:

    • 我需要为节点返回 (new Date(date)).toString() !== "Invalid Date"。还要注意 ? true : false 是多余的。在这里简单地返回表达式就足够了。
    • 在 IE8 中,new Date(date) 不会给您“无效日期”。
    • 这不是一个好的答案。 new Date(date) !== "Invalid Date"总是返回 true,因为左边的表达式将返回一个时间值为 NaN 的 Date 对象,它永远不会是 ===到一个字符串。由于类型转换,使用==“有效”。但由于日期字符串的解析在很大程度上仍然依赖于实现,因此依靠它来解析随机格式我们存在严重缺陷。
    • new Date("469") 结果为 1 月 1 日 469 日星期二 00:00:00 GMT+0200 (EET)
    • 这类似于错误接受的正确答案。 isDate('Mac OS X 10.14.2') 在这里返回 true。
    【解决方案3】:

    Date.parse() 就够了吗?

    查看其相关MDN Documentation page

    Date.parse 如果字符串日期有效,则返回时间戳。以下是一些用例:

    // /!\ from now (2021) date interpretation changes a lot depending on the browser
    Date.parse('01 Jan 1901 00:00:00 GMT') // -2177452800000
    Date.parse('01/01/2012') // 1325372400000
    Date.parse('153') // NaN (firefox) -57338928561000 (chrome)
    Date.parse('string') // NaN
    Date.parse(1) // NaN (firefox) 978303600000 (chrome)
    Date.parse(1000) // -30610224000000 from 1000 it seems to be treated as year
    Date.parse(1000, 12, 12) // -30610224000000 but days and month are not taken in account like in new Date(year, month,day...)
    Date.parse(new Date(1970, 1, 0)) // 2588400000
    // update with edge cases from comments
    Date.parse('4.3') // NaN (firefox) 986248800000 (chrome)
    Date.parse('2013-02-31') // NaN (firefox) 1362268800000 (chrome)
    Date.parse("My Name 8") // NaN (firefox) 996616800000 (chrome)
    

    【讨论】:

    • 注意这一点,因为它仍然会在二月返回无效日期,例如:2013-02-31
    • 另一个需要小心的原因 - 数字被解析为日期。 Date.parse("4.3")986270400000
    • 我尝试了上述两种“警告”案例:console.log(Date.parse("2013-02-31")); console.log(Date.parse("4.3"));并且在这两种情况下(在 Firefox 上)它都返回 NaN,所以对我来说,Date.parse 似乎没问题(无论如何,我在解析之前预先验证破折号和正确的长度)。
    • 对不起@Asmor,这不是一个正确的答案。 Date.parse 将解析任何带有数字的字符串。
    • Date.parse("My Name 8") 以 99662040000 的形式出现,这是错误的。我用过这个,现在很痛苦。
    【解决方案4】:

    new Date(date) === 'Invalid Date' 仅适用于 Firefox 和 Chrome。 IE8(我的机器上用于测试目的的那个)给出了 NaN。

    正如接受的答案所述,Date.parse(date) 也适用于数字。因此,为了解决这个问题,您还可以检查它是否不是数字(如果您想确认的话)。

    var parsedDate = Date.parse(date);
    
    // You want to check again for !isNaN(parsedDate) here because Dates can be converted
    // to numbers, but a failed Date parse will not.
    if (isNaN(date) && !isNaN(parsedDate)) {
        /* do your work */
    }
    

    【讨论】:

    • 我意识到这是几年后的事了,但isNan 不是一个函数;一审案件不正确。
    • 不起作用。如果dateFoostreet 1,则您的条件被评估为真。
    • @FabianPicone - 好吧,从技术上讲,它可以工作,但与其他基于parse 的解决方案有一个缺陷:Date.parse("<text here> <number here>") 可能被解析为“有效”日期,导致parsedDate不评估为NaN
    • 这会解析不是真实日期的类似日期的字符串,例如 2/31/2021。
    【解决方案5】:
    function isDate(dateStr) {
      return !isNaN(new Date(dateStr).getDate());
    }
    
    • 这适用于任何浏览器,因为它不依赖“无效日期”检查。
    • 这将适用于 ES6 之前的旧代码。
    • 这将在没有任何库的情况下工作。
    • 无论任何日期格式如何,这都会起作用。
    • 这不依赖于 Date.parse,当像“Spiderman 22”这样的值在日期字符串中时,它会失败。
    • 这并不要求我们编写任何正则表达式。

    【讨论】:

    • 您好!虽然这段代码可以解决问题,including an explanation 解决问题的方式和原因确实有助于提高帖子的质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提出问题的人。请edit您的回答添加解释并说明适用的限制和假设。
    • 当添加一个已被接受的答案和 19 个现有答案的 8 年老问题的答案时,指出您的答案所针对的问题的新方面非常重要,否则它可能看起来像重复答案并被删除。
    • 我已经添加了解释。感谢您的指导。
    • 小心,isDate('4.3') 和 isDate('xxx 8') 都返回 true
    • 不幸的是,关于不依赖Date.parse 的声明是不正确的,因为上述构造函数和使用字符串函数调用的Date() 构造函数几乎相同。
    【解决方案6】:

    这样的事情怎么样?它将测试它是日期对象还是日期字符串:

    function isDate(value) {
        var dateFormat;
        if (toString.call(value) === '[object Date]') {
            return true;
        }
        if (typeof value.replace === 'function') {
            value.replace(/^\s+|\s+$/gm, '');
        }
        dateFormat = /(^\d{1,4}[\.|\\/|-]\d{1,2}[\.|\\/|-]\d{1,4})(\s*(?:0?[1-9]:[0-5]|1(?=[012])\d:[0-5])\d\s*[ap]m)?$/;
        return dateFormat.test(value);
    }
    

    我应该提到,这不会测试 ISO 格式的字符串,但对 RegExp 做更多的工作应该会很好。

    【讨论】:

    • 这不会测试不是真实日期的字符串,例如 2/31/2021。
    • 是的,这可能不是最好的方法。匹配日期字符串的每个可能的组合是非常困难的。
    • 我测试字符串解析为日期,并且原始字符串中的日期与解析字符串中的日期匹配,以确保输入的是真实日期。 stackoverflow.com/a/66863366/7530620
    【解决方案7】:

    这里没有一个答案涉及检查日期是否无效,例如 2 月 31 日。此函数通过检查返回的月份是否等于原始月份并确保提供了有效的年份来解决这个问题。

    //expected input dd/mm/yyyy or dd.mm.yyyy or dd-mm-yyyy
    function isValidDate(s) {
      var separators = ['\\.', '\\-', '\\/'];
      var bits = s.split(new RegExp(separators.join('|'), 'g'));
      var d = new Date(bits[2], bits[1] - 1, bits[0]);
      return d.getFullYear() == bits[2] && d.getMonth() + 1 == bits[1];
    } 
    

    【讨论】:

    • 因为问题不在于检查字符串是否为“有效”日期,而只是检查字符串是否代表日期格式。
    • @Thizzer 好点。我不介意修复,但在重读你的问题时,我很困惑,因为你说 10 不应该验证,但应该允许时间戳。
    • xD 甚至没有注意到这一点,这是我早期的一个关于日期/时间戳的问题。我将在今天晚些时候尝试编辑问题。
    • @KapilRaghuwanshi javascript 日期使用从零开始的月份,因此您需要减 1 来创建正确的日期并加 1 来检查它是否等于原始月份
    • 这对我有用,因为例如,如果您使用“2/30/2020”创建一个新日期,Chrome 会为 2020 年 3 月 1 日创建一个有效日期。所以这是我唯一的事情可以检测这种无效日期。创建新的日期对象后,我将年、月、日与原始字符串进行了比较。
    【解决方案8】:

    使用正则表达式来验证它。

    isDate('2018-08-01T18:30:00.000Z');
    
    isDate(_date){
            const _regExp  = new RegExp('^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(.[0-9]+)?(Z)?$');
            return _regExp.test(_date);
        }
    

    【讨论】:

    • 这不会测试不是真实日期的字符串,例如 2/31/2021。
    【解决方案9】:

    参考了上面所有的cmets,我得出了一个解决方案。

    如果传递的Date 是 ISO 格式或需要针对其他格式进行操作,则此方法有效。

    var isISO = "2018-08-01T18:30:00.000Z";
    
    if (new Date(isISO) !== "Invalid Date" && !isNaN(new Date(isISO))) {
        if(isISO == new Date(isISO).toISOString()) {
            console.log("Valid date");
        } else {
            console.log("Invalid date");
        }
    } else {
        console.log("Invalid date");
    }
    

    你可以在 JSFiddle 上玩here

    【讨论】:

    • 这个解决方案最适合我,因为我的应用支持的日期字符串格式为YYYY-MM-DD,因此附加T00:00:00.000Z 并使用此解决方案检查有效字符串很简单。
    • 对于 javascript 这是有效的,但是如何在 typescript 中使用它?
    • 这不会测试不是真实日期的日期,例如 2/31/2021。
    • @JanineWhite Here new Date(isISO) 返回无效日期。
    • @NikhilZurunge 这个问题明确询问了多种格式,而不仅仅是 ISO 日期。
    【解决方案10】:

    这是一个仅使用Date.parse()的改进函数:

    function isDate(s) {
        if(isNaN(s) && !isNaN(Date.parse(s)))
            return true;
        else return false;
    }
    

    注意: Date.parse() 将解析数字:例如Date.parse(1) 将返回一个日期。所以这里我们检查s是否不是数字,如果是日期。

    【讨论】:

    • 这不起作用,因为通过“测试 2”将作为真实日期通过。在最新版本的 chrome 中测试
    • 这不会测试不真实的日期,例如 2021 年 2 月 31 日。此外,您不需要 if then 结构。您可以只返回条件,或将其分配给变量,然后返回变量,即 return (isNaN(s) && !isNaN(Date.parse(s)));
    【解决方案11】:

    我觉得没有一个答案能正确理解 OP 的要求。这里的问题是 JavaScript 可以将任何数字解析为有效日期,因为 Date 对象可以将 '3000' 之类的字符串解析为年份,并将返回一个有效的 Date 实例:

    new Date('3000')
    
    > Wed Jan 01 3000 02:00:00 GMT+0200 (Eastern European Standard Time)
    

    为了解决这个问题,我们可以通过传入第三个参数,在严格模式下使用Day.js库的解析方法。它记录在他们的String + Format 页面中。为了基于格式进行解析,我们还必须启用CustomParseFormat 插件。我假设你可以在这里使用 ESM 导入或设置像 Webpack 这样的编译器

    import dayjs from 'dayjs'
    import formatParser from 'dayjs/plugin/customParseFormat'
    
    dayjs.extend(formatParser)
    
    dayjs('3000', 'YYYY-MM-DD', true).isValid()
    
    > false
    

    【讨论】:

    • 这是 2021 年唯一有效的答案。
    【解决方案12】:

    我会这样做

    var myDateStr= new Date("2015/5/2");
    
    if( ! isNaN ( myDateStr.getMonth() )) {
        console.log("Valid date");
    }
    else {
        console.log("Invalid date");
    }
    

    播放here

    【讨论】:

    • 这在当前的 Chrome 中不起作用,可能在其他浏览器中。我将提供的字符串更改为EXAMPLE STRING 12345,它返回“有效日期”。
    • 这不会测试不是真实日期的字符串,例如 2/31/2021。
    【解决方案13】:

    我知道这是一个老问题,但我遇到了同样的问题,发现没有一个答案能正常工作 - 特别是从日期中剔除数字(1,200,345 等),这是最初的问题。这是我能想到的一种相当非正统的方法,它似乎有效。请指出是否存在会失败的情况。

    if(sDate.toString() == parseInt(sDate).toString()) return false;
    

    这是淘汰数字的路线。因此,整个函数可能如下所示:

    function isDate(sDate) {  
      if(sDate.toString() == parseInt(sDate).toString()) return false; 
      var tryDate = new Date(sDate);
      return (tryDate && tryDate.toString() != "NaN" && tryDate != "Invalid Date");  
    }
    
    console.log("100", isDate(100));
    console.log("234", isDate("234"));
    console.log("hello", isDate("hello"));
    console.log("25 Feb 2018", isDate("25 Feb 2018"));
    console.log("2009-11-10T07:00:00+0000", isDate("2009-11-10T07:00:00+0000"));

    【讨论】:

    • console.log("hello 1 ", isDate("hello 1 ")); 返回真
    • 你是对的!你有解决方案吗?到目前为止,我认为这里的答案都没有真正恰当地解决这个问题!
    • "100%",百分比,返回true
    【解决方案14】:

    这个可调用函数完美运行,有效日期返回 true。 请务必使用 ISO 格式的日期(yyyy-mm-dd 或 yyyy/mm/dd)调用:

    function validateDate(isoDate) {
    
        if (isNaN(Date.parse(isoDate))) {
            return false;
        } else {
            if (isoDate != (new Date(isoDate)).toISOString().substr(0,10)) {
                return false;
            }
        }
        return true;
    }
    

    【讨论】:

    • 很好,但并不能完全回答问题。具体来说,它不适用于给出的示例之一“2009-11-10T07:00:00+0000”。
    • 不要认为它应该有效 validateDate('2016-12-30T08:00:00.000Z') // false
    • 不管行不通,都可以简化为return !isNaN(Date.parse(isoDate)) || isoDate == new Date(isoDate).toISOString().substr(0,10);
    【解决方案15】:

    这是一个极简版本。

    var isDate = function (date) {
        return!!(function(d){return(d!=='Invalid Date'&&!isNaN(d))})(new Date(date));
    }
    

    【讨论】:

    • 仍然不适用于我的示例:isDate("  1")
    • @Tom 在确定它是否是日期之前,您应该检查该值是否包含空格字符。您的问题是一种特殊情况,需要由您的控制器逻辑处理。
    • 不应要求检查空格字符,因为字符串 Jan. 1, 2020 是包含空格的有效日期。您的方法没有考虑到这一点。
    • 这不会测试不是真实日期的字符串,例如 2/31/2021。
    【解决方案16】:

    是否可以检查对象是否可以使用与日期相关的函数来查找它是否是日期对象?

    喜欢

    var l = new Date();
    var isDate = (l.getDate !== undefined) ? true; false;
    

    【讨论】:

      【解决方案17】:

      好的,这是一个老问题,但我在这里查看解决方案时找到了另一个解决方案。对我来说,检查日期对象中是否存在函数 getTime():

      const checkDate = new Date(dateString);
      
      if (typeof checkDate.getTime !== 'function') {
        return;
      }
      

      【讨论】:

        【解决方案18】:

        我觉得这个解决方案非常好:

        const DateTime = require('luxon').DateTime;
        
        isDateValid(stringDate) {
          let date = DateTime.fromFormat(stringDate, 'd-M-y');
          if (date.invalid === null) {
            return date.toJSDate();
          }
          date = DateTime.fromFormat(stringDate, 'd,M,y');
          if (date.invalid === null) {
            return date.toJSDate();
          }
          date = DateTime.fromFormat(stringDate, 'y-M-d');
          if (date.invalid === null) {
            return date.toJSDate();
          }
          date = DateTime.fromFormat(stringDate, 'y,M,d');
          if (date.invalid === null) {
            return date.toJSDate();
          }
          date = DateTime.fromFormat(stringDate, 'y.M.d');
          if (date.invalid === null) {
            return date.toJSDate();
          }
          date = DateTime.fromFormat(stringDate, 'd.M.y');
          if (date.invalid === null) {
            return date.toJSDate();
          }
          date = DateTime.fromFormat(stringDate, 'y/M/d');
          if (date.invalid === null) {
            return date.toJSDate();
          }
          date = DateTime.fromFormat(stringDate, 'd/M/y');
          if (date.invalid === null) {
            return date.toJSDate();
          }
          return false;
        }
        
        isDateValid('30.12.86'); //true
        isDateValid('30/12/86'); //true
        isDateValid('86-12-40'); //false
        

        您可以轻松添加更多格式

        【讨论】:

          【解决方案19】:

          这就是我最终的做法。这不会涵盖所有格式。 你必须做出相应的调整。我可以控制格式,所以它对我有用

          function isValidDate(s) {
                      var dt = "";
                      var bits = [];
                      if (s && s.length >= 6) {
                          if (s.indexOf("/") > -1) {
                              bits = s.split("/");
                          }
                          else if (s.indexOf("-") > -1) {
                              bits = s.split("-");
                          }
                          else if (s.indexOf(".") > -1) {
                              bits = s.split(".");
                          }
                          try {
                              dt = new Date(bits[2], bits[0] - 1, bits[1]);
                          } catch (e) {
                              return false;
                          }
                          return (dt.getMonth() + 1) === parseInt(bits[0]);
                      } else {
                          return false;
                      }
                  }
          

          【讨论】:

            【解决方案20】:

            此函数验证格式为 m/d/yyyy 或 mm/dd/yyyy 的输入字符串是否可以转换为日期,并且该日期是与输入字符串匹配的有效日期。添加更多条件检查以验证其他格式。

            /**
             * Verify if a string is a date
             * @param {string} sDate - string that should be formatted m/d/yyyy or mm/dd/yyyy
             * @return {boolean} whether string is a valid date
             */
            function isValidDate(sDate) {
              let newDate = new Date(sDate);
              console.log(sDate + " date conversion: " + newDate);
              let isDate = (!isNaN(newDate.getTime()));
              console.log(sDate + " is a date: " + isDate);
              if (isDate) {
                let firstSlash = sDate.indexOf("/");
                let secondSlash = sDate.indexOf("/",firstSlash+1);
                let originalDateString = parseInt(sDate.slice(0,firstSlash),10) + "/" + parseInt(sDate.slice(firstSlash+1,secondSlash),10) + "/" + parseInt(sDate.slice(secondSlash+1),10);
                let newDateString = (newDate.getMonth()+1) + "/" + (newDate.getDate()) + "/" + (newDate.getFullYear());
                isDate = (originalDateString == newDateString);
                console.log(originalDateString + " matches " + newDateString + ": " + isDate);
              }
              return isDate;
            }
            

            【讨论】:

              猜你喜欢
              • 2020-06-23
              • 1970-01-01
              • 2018-06-15
              • 1970-01-01
              • 1970-01-01
              • 2012-06-17
              • 2011-10-06
              • 1970-01-01
              相关资源
              最近更新 更多