【问题标题】:Prevent moment.js accepting an integer as a valid ISO8601 date防止 moment.js 接受整数作为有效的 ISO8601 日期
【发布时间】:2021-04-22 10:24:48
【问题描述】:

我有一些用于创建仪表板小部件的 API。这些 API 返回传递给 Google Charts 的基本名称/值数据对。 Moment.js 检查该值是否为 ISO8601 日期,如果是,则作为日期实例传递给 Google Charts。

但是,如果日期是一个简单的整数,则 ISO_8601 isValid 检查当前返回 true,例如1234:

var myInt = 1234;
if (moment(myInt, moment.ISO_8601, true).isValid()) {
    console.log("Valid!");
}

我找不到在 moment.js 代码中强制使用日期格式的必要功能,所以这个残酷的 hack 暂时有效:

var myInt = 1234;
if (JSON.stringify(myInt).includes("T") && moment(myInt, moment.ISO_8601, true).isValid()) {
    console.log("Valid!");
}

有没有正确的方式使用moment.js配置isValid()检查?

我的 API 中的日期格式是 yyyy-mm-ddThh:mm:ss(最后没有 Z)。

【问题讨论】:

    标签: javascript momentjs


    【解决方案1】:

    根据THIS的回答,当使用严格解析(最后一个参数设置为true)时,您还应该指定解析格式,以避免出现您描述的情况。正如许多用户所注意到的,指定字符串格式而不是使用 moment.ISO_8601 可以正常工作。

    alert(isISODateValid(123)); //false
    alert(isISODateValid("2011-10-10T14:48:00")); //true
    alert(isISODateValid("2011-10-10T14:48:00Z")); //true
    
    function isISODateValid(date) {
    
      return moment(date.toString().replaceAll("Z",""), "YYYY-MM-DDTHH:mm:ss", true).isValid();
    
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>

    编辑:更新 sn-p - 如果日期包含“Z”后缀,请在解析验证源日期格式之前将其删除

    【讨论】:

    • 嗯,很有趣,谢谢。这里的挑战是,如果 API 返回日期带有Z 后缀——一个完全有效的 ISO8601 格式,那么我们必须记住更改解析格式。我认为你的解决方案有多个isValid 检查可能是解决方案...if (moment(1234, "YYYY-MM-DDTHH:mm:ss", true).isValid() || moment(1234, "YYYY-MM-DDTHH:mm:ssZ", true).isValid())
    • 您还可以从“Z”字母中删除所有传入的日期以匹配格式,因为“Z”仅表示时间戳中的偏移量为零,并且在解析方面没有任何改变。跨度>
    • 根据维基百科:en.wikipedia.org/wiki/ISO_8601 零偏移量,除了具有特殊表示“Z”外,还可以用数字表示为“+00:00”、“+0000”或“+00”。
    • 好答案。谢谢你。在时间允许的情况下,我会奖励赏金。
    • 请检查上面的帖子编辑。一个简单的函数,允许最小化验证所需的代码,也没有不必要的重复
    【解决方案2】:

    你可以在你把它传到那一刻之前证明这个刺痛。?我从这个post中举了一个例子

    /**
     * RegExp to test a string for a full ISO 8601 Date
     * Does not do any sort of date validation, only checks if the string is according to the ISO 8601 spec.
     *  YYYY-MM-DDThh:mm:ss
     *  YYYY-MM-DDThh:mm:ssTZD
     *  YYYY-MM-DDThh:mm:ss.sTZD
     * @see: https://www.w3.org/TR/NOTE-datetime
     * @type {RegExp}
     */
    var ISO_8601_FULL = /^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d(\.\d+)?(([+-]\d\d:\d\d)|Z)?$/i
    
    
    // Usage:
    
    ISO_8601_FULL.test( "2016-05-24T15:54:14.876Z" )  // true
    ISO_8601_FULL.test( "2002-12-31T23:00:00+01:00" ) // true
    ISO_8601_FULL.test( "2016-02-01" )                // false
    ISO_8601_FULL.test( "2016" )                      // false
    
    if (ISO_8601_FULL.test(myDate) && moment(myDate, moment.ISO_8601, true).isValid()) {
        console.log("Valid!");
    }
    

    我想日期不应该是整数。

    【讨论】:

    • 问题1234的具体值怎么样(作为数字,而不是作为字符串)?
    • 这太复杂了,而且在性能方面非常昂贵。
    【解决方案3】:

    既然您说:“我的 API 中的日期格式是 yyyy-mm-ddThh:mm:ss(最后没有 Z)”,解析它的最佳方法是明确传递您期望时刻的格式,使用正确的时刻格式 tokens 而不是使用 moment.ISO_8601

    因此,在您的情况下,只需使用moment(myInt, "YYYY-MM-DDTHH:mm:ss", true),如代码片段所示:

    function checkValid(input) {
      if (moment(input, "YYYY-MM-DDTHH:mm:ss", true).isValid()) {
        console.log(input + " is valid!");
      }
    }
    
    checkValid(1234);
    checkValid("2021-04-27T20:40:15");
    checkValid("2021-04-27T20:40:15Z");
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>

    请注意,末尾的Z 代表时区偏移量UTC+0,如果您有它,则将其考虑在内,而没有它,则将输入解析为本地时间(请参阅Local vs UTC vs Offset 指南)

    作为旁注,moment.ISO_86012.25.0 之前的时刻版本中的工作方式与您所期望的一样:

    function checkValid(input) {
      if (moment(input, moment.ISO_8601, true).isValid()) {
        console.log(input + " is valid!");
      }
    }
    
    checkValid(1234);
    checkValid("2021-04-27T20:40:15");
    checkValid("2021-04-27T20:40:15Z");
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>

    【讨论】:

      【解决方案4】:

      有趣的是字符串和数字之间的区别。如果它是一个数字,它被解释为自 epoc 以来的毫秒数,这在计算机语言中非常有用,但显然并不总是要求的内容,也不是每个开发人员都清楚。这可以通过类型检查 (typeof input != 'string') 轻松避免。

      另一个变体更令人困惑:"12345" 无效。好的。但是"1234" 被解释为一年,同时“34”似乎被解释为以分钟为单位的时间偏移(Sun Jan 01 1234 00:00:00 GMT+0034)。对我来说,这显然看起来像是库中的一个错误,因为为了不同的目的多次解析相同的数字是毫无用处的。但在此问题修复后,"1234" 仍然是标准 ISO 8601 中定义的有效日期(仅限年份)

      https://en.wikipedia.org/wiki/ISO_8601

      为了降低精度,[17] 可以从任何日期和时间表示中删除任意数量的值,但顺序是从最不重要到最重要。例如,“2004-05”是一个有效的 ISO 8601 日期,表示 2004 年 5 月(第五个月)。这种格式永远不会表示 2004 年未指定月份的第 5 天,也不会表示从2004 年到 2005 年。

      顺便说一句:"543210" 也是有效的,表示 "5432-10",或 5432 年 10 月

      function checkValid(input) {
        m = moment(input, true);
        console.log(input + "  type: " + typeof input + "  valid: " + m.isValid() + "  result:" + m.toString());
      }
      
      checkValid(1234);
      checkValid("1234");
      checkValid(12345);
      checkValid("12345");
      checkValid("2021-04-27T20:40:15");
      checkValid("2021-04-27T20:40:15Z");
      <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>

      【讨论】:

        猜你喜欢
        • 2016-02-10
        • 1970-01-01
        • 2012-11-25
        • 2014-02-27
        • 2016-09-04
        • 2020-02-26
        • 1970-01-01
        • 2017-04-04
        • 1970-01-01
        相关资源
        最近更新 更多