【发布时间】:2011-03-09 18:07:45
【问题描述】:
有没有人有一个好的正则表达式模式来匹配 iso 日期时间?
即:2010-06-15T00:00:00
【问题讨论】:
-
我使用
/^(\d{4})-0?(\d+)-0?(\d+)[T ]0?(\d+):0?(\d+):0?(\d+)$/,(但这不是最严格的).. 转换为 Date 是另一回事 :)
标签: javascript regex datetime iso
有没有人有一个好的正则表达式模式来匹配 iso 日期时间?
即:2010-06-15T00:00:00
【问题讨论】:
/^(\d{4})-0?(\d+)-0?(\d+)[T ]0?(\d+):0?(\d+):0?(\d+)$/,(但这不是最严格的).. 转换为 Date 是另一回事 :)
标签: javascript regex datetime iso
Brocks 的答案很好,但应该以 ^ 开头并以 $ 结尾,以便在您尝试匹配的只是日期字符串时不允许使用前缀/后缀字符。
【讨论】:
这里对大多数答案的解释太多了,这是@Sergey answer 的简短变体,解决了一些奇怪的情况(例如2020-00-00),这个RegExp 只关心yyyy-MM-dd 日期:
// yyyy-MM-dd
^\d{4}-([0][1-9]|1[0-2])-([0-2][1-9]|[1-3]0|3[01])$
这个也不关心每个月的天数,比如2020-11-31(因为11月只有30天)。
我的用例是将String 转换为Date(来自API 参数),我只需要知道输入字符串不包含奇怪的东西,我会针对下一个验证一个实际的 Date 对象。
【讨论】:
从 1900 年到 2999 年进行 02/29 验证
(((2000|2400|2800|((19|2[0-9])(0[48]|[2468][048]|[13579][26])))-02-29)|(((19|2[0-9])[0-9]{2})-02-(0[1-9]|1[0-9]|2[0-8]))|(((19|2[0-9])[0-9]{2})-(0[13578]|10|12)-(0[1-9]|[12][0-9]|3[01]))|(((19|2[0-9])[0-9]{2})-(0[469]|11)-(0[1-9]|[12][0-9]|30)))T([01][0-9]|[2][0-3]):[0-5][0-9]:[0-5][0-9]\.[0-9]{3}Z
【讨论】:
我已经制作了这个正则表达式,并解决了 Javascript 的 .toISOString() 方法对日期的验证。
^[0-9]{4}-((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01])|(0[469]|11)-(0[1-9]|[12][0-9]|30)|(02)-(0[1-9]|[12][0-9]))T(0[0-9]|1[0-9]|2[0-3]):(0[0-9]|[1-5][0-9]):(0[0-9]|[1-5][0-9])\.[0-9]{3}Z$
考虑:
不考虑:
示例日期: 2019-11-15T13:34:22.178Z
直接在 Chrome 控制台中运行的示例: /^[0-9]{4}-((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01])|(0[469]|11)-(0[1-9]|[12][0-9]|30)|(02)-(0[1-9]|[12][0-9]))T(0[0-9]|1[0-9]|2[0-3]):(0[0-9]|[1-5][0-9]):(0[0-9]|[1-5][0-9])\.[0-9]{3}Z$/.test("2019-11-15T13:34:22.178Z");
正则表达式流程图(Regexper):
【讨论】:
要匹配 ISO 日期,例如 2017-09-22,您可以使用此正则表达式:
^\d{4}-([0]\d|1[0-2])-([0-2]\d|3[01])$
它将匹配任何数字年份、00-12 范围内两位数指定的任何月份以及 00-31 范围内两位数指定的任何日期
【讨论】:
我将最佳答案改写为更简洁的内容。不是写出三个可选模式中的每一个,而是将元素嵌套为可选语句。
/[+-]?\d{4}(-[01]\d(-[0-3]\d(T[0-2]\d:[0-5]\d:?([0-5]\d(\.\d+)?)?[+-][0-2]\d:[0-5]\dZ?)?)?)?/
我很好奇这种方法是否有缺点?
你可以在这里找到我建议的答案的测试:http://regexr.com/3e0lh
【讨论】:
[+-][0-2]\d:[0-5]\d 可选使其工作:[+-]?\d{4}(-[01]\d(-[0-3]\d(T[0-2]\d:[0-5]\d:?([0-5]\d(\.\d+)?)?([+-][0-2]\d:[0-5]\d)?Z?)?)?)?
\d{4} 部分匹配的匹配部分。
这是一个检查 ISO 8601 日期格式的正则表达式,包括闰年和短长月。要运行它,您需要“忽略空白”。没有空格的压缩版本在 regexlib 上:http://regexlib.com/REDetails.aspx?regexp_id=3344
ISO 8601 还有更多内容 - 此正则表达式只关心日期,但您可以轻松扩展它以支持时间验证,这并不难。
更新:现在可以使用 javascript(没有后视)
^(?:
(?=
[02468][048]00
|[13579][26]00
|[0-9][0-9]0[48]
|[0-9][0-9][2468][048]
|[0-9][0-9][13579][26]
)
\d{4}
(?:
(-|)
(?:
(?:
00[1-9]
|0[1-9][0-9]
|[1-2][0-9][0-9]
|3[0-5][0-9]
|36[0-6]
)
|
(?:01|03|05|07|08|10|12)
(?:
\1
(?:0[1-9]|[12][0-9]|3[01])
)?
|
(?:04|06|09|11)
(?:
\1
(?:0[1-9]|[12][0-9]|30)
)?
|
02
(?:
\1
(?:0[1-9]|[12][0-9])
)?
|
W(?:0[1-9]|[1-4][0-9]|5[0-3])
(?:
\1
[1-7]
)?
)
)?
)$
|
^(?:
(?!
[02468][048]00
|[13579][26]00
|[0-9][0-9]0[48]
|[0-9][0-9][2468][048]
|[0-9][0-9][13579][26]
)
\d{4}
(?:
(-|)
(?:
(?:
00[1-9]
|0[1-9][0-9]
|[1-2][0-9][0-9]
|3[0-5][0-9]
|36[0-5]
)
|
(?:01|03|05|07|08|10|12)
(?:
\2
(?:0[1-9]|[12][0-9]|3[01])
)?
|
(?:04|06|09|11)
(?:
\2
(?:0[1-9]|[12][0-9]|30)
)?
|
(?:02)
(?:
\2
(?:0[1-9]|1[0-9]|2[0-8])
)?
|
W(?:0[1-9]|[1-4][0-9]|5[0-3])
(?:
\2
[1-7]
)?
)
)?
)$
为了满足时间,在混合物中添加这样的东西(来自:http://underground.infovark.com/2008/07/22/iso-date-validation-regex/):
([T\s](([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)?(\15([0-5]\d))?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?
【讨论】:
对于严格的完整日期时间,包括毫秒,每个 the W3C's take on the spec。:
//-- Complete precision:
/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/
//-- No milliseconds:
/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z)/
//-- No Seconds:
/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z)/
//-- Putting it all together:
/(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/
.
实际ISO 8601:2004(E) doc 允许的其他变化:
/********************************************
** No time-zone varients:
*/
//-- Complete precision:
/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+/
//-- No milliseconds:
/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d/
//-- No Seconds:
/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d/
//-- Putting it all together:
/(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+)|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d)|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d)/
警告:这一切很快就会变得一团糟,而且它仍然允许某些废话,例如第 14 个月。 此外,ISO 8601:2004(E) 允许其他几种变体。
.“2010-06-15T00:00:00”是不合法的,因为它没有指定时区。
【讨论】:
(?: ) 而不是( ) 来避免捕获一个组。例如\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+(?:[+-][0-2]\d:[0-5]\d|Z) 第一个正则表达式。
ISO 8601 规范允许多种日期格式。关于如何做到这一点here 有一个平庸的解释。 Javascript 的日期输入格式与未指定时区的简单日期的 ISO 格式之间存在相当小的差异,可以使用string substitution 轻松缓解。完全支持 ISO-8601 规范并非易事。
这是一个参考示例,我不保证它是完整的,尽管它从上述 Wikipedia 页面解析了非持续时间。
下面是一个例子,你也可以看到它是output on ideone。不幸的是,它不能按规范工作,因为它没有正确实施数周。 ISO-8601 中第 01 周的定义很重要,需要浏览日历来确定第一周从哪里开始,以及它在指定年份的天数方面的确切含义。这可能很容易纠正(我只是厌倦了玩它)。
function parseISODate (input) {
var iso = /^(\d{4})(?:-?W(\d+)(?:-?(\d+)D?)?|(?:-(\d+))?-(\d+))(?:[T ](\d+):(\d+)(?::(\d+)(?:\.(\d+))?)?)?(?:Z(-?\d*))?$/;
var parts = input.match(iso);
if (parts == null) {
throw new Error("Invalid Date");
}
var year = Number(parts[1]);
if (typeof parts[2] != "undefined") {
/* Convert weeks to days, months 0 */
var weeks = Number(parts[2]) - 1;
var days = Number(parts[3]);
if (typeof days == "undefined") {
days = 0;
}
days += weeks * 7;
var months = 0;
}
else {
if (typeof parts[4] != "undefined") {
var months = Number(parts[4]) - 1;
}
else {
/* it's an ordinal date... */
var months = 0;
}
var days = Number(parts[5]);
}
if (typeof parts[6] != "undefined" &&
typeof parts[7] != "undefined")
{
var hours = Number(parts[6]);
var minutes = Number(parts[7]);
if (typeof parts[8] != "undefined") {
var seconds = Number(parts[8]);
if (typeof parts[9] != "undefined") {
var fractional = Number(parts[9]);
var milliseconds = fractional / 100;
}
else {
var milliseconds = 0
}
}
else {
var seconds = 0;
var milliseconds = 0;
}
}
else {
var hours = 0;
var minutes = 0;
var seconds = 0;
var fractional = 0;
var milliseconds = 0;
}
if (typeof parts[10] != "undefined") {
/* Timezone adjustment, offset the minutes appropriately */
var localzone = -(new Date().getTimezoneOffset());
var timezone = parts[10] * 60;
minutes = Number(minutes) + (timezone - localzone);
}
return new Date(year, months, days, hours, minutes, seconds, milliseconds);
}
print(parseISODate("2010-06-29T15:33:00Z-7"))
print(parseISODate("2010-06-29 06:14Z"))
print(parseISODate("2010-06-29T06:14Z"))
print(parseISODate("2010-06-29T06:14:30.2034Z"))
print(parseISODate("2010-W26-2"))
print(parseISODate("2010-180"))
【讨论】:
不确定它是否与您要解决的潜在问题相关,但您可以将 ISO 日期字符串作为构造函数 arg 传递给 Date() 并从中获取对象。构造函数在将字符串强制转换为日期方面实际上非常灵活。
【讨论】: