【发布时间】:2011-11-18 16:59:41
【问题描述】:
什么是检查值是否为有效日期的简单方法,允许任何已知的日期格式。
例如,我的值 10-11-2009、10/11/2009、2009-11-10T07:00:00+0000 都应该被识别为日期值,而值 200、10、350 则不应被识别为日期值。如果可能的话,最简单的检查方法是什么?因为时间戳也是允许的。
【问题讨论】:
什么是检查值是否为有效日期的简单方法,允许任何已知的日期格式。
例如,我的值 10-11-2009、10/11/2009、2009-11-10T07:00:00+0000 都应该被识别为日期值,而值 200、10、350 则不应被识别为日期值。如果可能的话,最简单的检查方法是什么?因为时间戳也是允许的。
【问题讨论】:
这是一个老问题,但还有其他新问题,例如:
作为这个副本的副本被关闭,所以我认为在这里添加一些新信息很重要。我写它是因为我害怕人们实际上复制并粘贴了此处发布的一些代码并在生产中使用它。
这里的大多数答案 要么 使用了一些复杂的正则表达式,它们只匹配一些非常特定的格式并且实际上做错了(比如匹配 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,还有其他库:
我创建了 immoment 模块,它类似于 Moment(的子集),但不会因现有对象的突变而引起意外(有关更多信息,请参阅 the docs)。
今天我建议使用Luxon 来进行日期/时间操作,而不是 Moment,它(与 Moment 不同)使所有对象都不可变,因此不会出现与日期的隐式突变相关的令人讨厌的意外。
另见:
Rob Gravelle 关于 JavaScript 日期解析库的系列文章:
当然,任何人都可以尝试重新发明轮子,编写正则表达式(但请在这样做之前实际阅读 ISO 8601 和 RFC 3339)或使用随机数据调用内置构造函数进行解析'Invalid Date' 之类的错误消息(您确定此消息在所有平台上完全相同吗?在所有语言环境中?将来?)或您可以使用经过测试的解决方案并利用你的时间来改进它,而不是重新发明它。此处列出的所有库都是开源的免费软件。
【讨论】:
moment("whatever 123").isValid() 返回true。
moment("06/22/2015", "DD/MM/YYYY", true).isValid(); 明确提供预期的日期格式,并带有参数true 表示严格检查。我用更多信息和更好的例子更新了我的答案。
这就是我在我正在开发的应用程序中解决这个问题的方法:
根据 krillgar 的反馈进行了更新:
var isDate = function(date) {
return (new Date(date) !== "Invalid Date") && !isNaN(new Date(date));
}
【讨论】:
new Date(date) 不会给您“无效日期”。
new Date(date) !== "Invalid Date" 将总是返回 true,因为左边的表达式将返回一个时间值为 NaN 的 Date 对象,它永远不会是 ===到一个字符串。由于类型转换,使用==“有效”。但由于日期字符串的解析在很大程度上仍然依赖于实现,因此依靠它来解析随机格式我们存在严重缺陷。
isDate('Mac OS X 10.14.2') 在这里返回 true。
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)
【讨论】:
Date.parse("4.3") 是 986270400000。
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 不是一个函数;一审案件不正确。
date 是Foostreet 1,则您的条件被评估为真。
parse 的解决方案有一个缺陷:Date.parse("<text here> <number here>") 可能被解析为“有效”日期,导致parsedDate不评估为NaN。
function isDate(dateStr) {
return !isNaN(new Date(dateStr).getDate());
}
【讨论】:
Date.parse 的声明是不正确的,因为上述构造函数和使用字符串函数调用的Date() 构造函数几乎相同。
这样的事情怎么样?它将测试它是日期对象还是日期字符串:
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 日。此函数通过检查返回的月份是否等于原始月份并确保提供了有效的年份来解决这个问题。
//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];
}
【讨论】:
使用正则表达式来验证它。
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);
}
【讨论】:
参考了上面所有的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 并使用此解决方案检查有效字符串很简单。
new Date(isISO) 返回无效日期。
这是一个仅使用Date.parse()的改进函数:
function isDate(s) {
if(isNaN(s) && !isNaN(Date.parse(s)))
return true;
else return false;
}
注意: Date.parse() 将解析数字:例如Date.parse(1) 将返回一个日期。所以这里我们检查s是否不是数字,如果是日期。
【讨论】:
我觉得没有一个答案能正确理解 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
【讨论】:
我会这样做
var myDateStr= new Date("2015/5/2");
if( ! isNaN ( myDateStr.getMonth() )) {
console.log("Valid date");
}
else {
console.log("Invalid date");
}
播放here
【讨论】:
EXAMPLE STRING 12345,它返回“有效日期”。
我知道这是一个老问题,但我遇到了同样的问题,发现没有一个答案能正常工作 - 特别是从日期中剔除数字(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 ")); 返回真
这个可调用函数完美运行,有效日期返回 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;
}
【讨论】:
return !isNaN(Date.parse(isoDate)) || isoDate == new Date(isoDate).toISOString().substr(0,10);
这是一个极简版本。
var isDate = function (date) {
return!!(function(d){return(d!=='Invalid Date'&&!isNaN(d))})(new Date(date));
}
【讨论】:
isDate("&nbsp; 1")
是否可以检查对象是否可以使用与日期相关的函数来查找它是否是日期对象?
喜欢
var l = new Date();
var isDate = (l.getDate !== undefined) ? true; false;
【讨论】:
好的,这是一个老问题,但我在这里查看解决方案时找到了另一个解决方案。对我来说,检查日期对象中是否存在函数 getTime():
const checkDate = new Date(dateString);
if (typeof checkDate.getTime !== 'function') {
return;
}
【讨论】:
我觉得这个解决方案非常好:
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
您可以轻松添加更多格式
【讨论】:
这就是我最终的做法。这不会涵盖所有格式。 你必须做出相应的调整。我可以控制格式,所以它对我有用
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;
}
}
【讨论】:
此函数验证格式为 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;
}
【讨论】: