阻止 moment.js 接受整数作为有效的 ISO8601 日期
Prevent moment.js accepting an integer as a valid ISO8601 date
我有一些 API 用于创建仪表板小部件。传递给 Google 图表的 API 的 return 基本 name/value 数据对。 Moment.js 检查该值是否为 ISO8601 日期,如果是,则作为日期实例传递给 Google 图表。
但是,ISO_8601 isValid
检查目前 return 如果日期是一个简单的整数,例如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
)。
你可以在把它传递给当下之前证明它的存在。?我从这个 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!");
}
我想日期应该不是整数。
根据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>
编辑:更新片段 - 如果日期包含“Z”后缀,在解析验证源日期格式之前将其删除
由于您声明:“我的 API 的日期格式是 yyyy-mm-ddThh:mm:ss(末尾没有 Z)”,解析它的最佳方法是使用正确的时刻格式 tokens instead of using 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,如果你有它,moment会考虑到它,如果没有它,moment会将输入解析为本地时间(见Local vs UTC vs Offset指南)
作为旁注,moment.ISO_8601
在 2.25.0
之前的 moment 版本中的工作方式与您预期的一样:
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>
有趣的是字符串和数字之间的区别。如果它是一个数字,它被解释为自 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
For reduced precision,[17] any number of values may be dropped from any of the date and time representations, but in the order from the least to the most significant. For example, "2004-05" is a valid ISO 8601 date, which indicates May (the fifth month) 2004. This format will never represent the 5th day of an unspecified month in 2004, nor will it represent a time-span extending from 2004 into 2005.
顺便说一句:"543210"
也是有效的,表示 "5432-10"
,或 5432 年的十月
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>
我有一些 API 用于创建仪表板小部件。传递给 Google 图表的 API 的 return 基本 name/value 数据对。 Moment.js 检查该值是否为 ISO8601 日期,如果是,则作为日期实例传递给 Google 图表。
但是,ISO_8601 isValid
检查目前 return 如果日期是一个简单的整数,例如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
)。
你可以在把它传递给当下之前证明它的存在。?我从这个 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!");
}
我想日期应该不是整数。
根据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>
编辑:更新片段 - 如果日期包含“Z”后缀,在解析验证源日期格式之前将其删除
由于您声明:“我的 API 的日期格式是 yyyy-mm-ddThh:mm:ss(末尾没有 Z)”,解析它的最佳方法是使用正确的时刻格式 tokens instead of using 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,如果你有它,moment会考虑到它,如果没有它,moment会将输入解析为本地时间(见Local vs UTC vs Offset指南)
作为旁注,moment.ISO_8601
在 2.25.0
之前的 moment 版本中的工作方式与您预期的一样:
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>
有趣的是字符串和数字之间的区别。如果它是一个数字,它被解释为自 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
For reduced precision,[17] any number of values may be dropped from any of the date and time representations, but in the order from the least to the most significant. For example, "2004-05" is a valid ISO 8601 date, which indicates May (the fifth month) 2004. This format will never represent the 5th day of an unspecified month in 2004, nor will it represent a time-span extending from 2004 into 2005.
顺便说一句:"543210"
也是有效的,表示 "5432-10"
,或 5432 年的十月
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>