DD-MON-YY格式JS正则日期验证:31日判定错误求助
DD-MON-YY日期验证错误:3月、5月31日被误判无效
我多年来一直受此问题困扰,如今终于无法忍受。使用以下JS正则验证DD-MON-YY格式日期时,会错误判定3月(Mar)、5月(May)的31日为无效日期,但这两个月份实际都有31天。我反复检查正则却找不到问题根源,希望能得到他人协助排查。
原验证代码
function isdateField1(currVal) { if (currVal == '') return false; //Declare Regex var rxDatePattern = /^(\d{1,2})(-)(?:|(jan)|(feb)|(mar)|(apr)|(may)|(jun)|(jul)|(aug)|(sep)|(oct)|(nov)|(dec))(-)(\d{2})$/i; var dtArray = currVal.match(rxDatePattern); if (dtArray == null) return false; var dtDay = parseInt(dtArray[1]); var dtMonth = parseInt(dtArray[3]); var dtYear = parseInt(dtArray[17]); if (isNaN(dtMonth)) { for (var i = 4; i <= 15; i++) { if ((dtArray[i])) { dtMonth = i - 3; break; } } } if (dtMonth < 1 || dtMonth > 12) return false; else if (dtDay < 1 || dtDay > 31) return false; else if ((dtMonth == 4 || dtMonth == 6 || dtMonth == 9 || dtMonth == 11) && dtDay == 31) return false; else if (dtMonth == 2) { var isleap = (dtYear % 4 == 0 && (dtYear % 100 != 0 || dtYear % 400 == 0)); if (dtDay > 29 || (dtDay == 29 && !isleap)) return false; } return true; }
问题根源
- 月份索引计算错误:
正则里(mar)是第5个捕获组、(may)是第7个捕获组,但代码循环时用dtMonth = i - 3,导致:- 匹配
mar时,i=5 → 5-3=2(被当成2月,2月无31天,直接判无效) - 匹配
may时,i=7 →7-3=4(被当成4月,4月只有30天,判无效)
- 匹配
- 年份索引错误:正则最后一个年份分组是第16个,但代码取了
dtArray[17],会得到undefined,转成数字后为NaN,导致闰年判断逻辑失效。 - 正则冗余空选项:非捕获组里的
?:|允许月份为空,不符合DD-MON-YY格式要求,还干扰分组逻辑。
修复方案
方案1:用映射表简化月份判断(推荐)
直接通过月份字符串映射到对应数字,避免分组索引出错:
function isdateField1(currVal) { if (currVal === '') return false; // 简化正则,去掉空选项,结构更清晰 const rxDatePattern = /^(\d{1,2})-(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)-(\d{2})$/i; const dtArray = currVal.match(rxDatePattern); if (!dtArray) return false; const dtDay = parseInt(dtArray[1]); const dtYear = parseInt(dtArray[3]); // 月份字符串转数字 const monthMap = { jan: 1, feb: 2, mar: 3, apr:4, may:5, jun:6, jul:7, aug:8, sep:9, oct:10, nov:11, dec:12 }; const dtMonth = monthMap[dtArray[2].toLowerCase()]; // 边界校验 if (dtMonth < 1 || dtMonth > 12) return false; if (dtDay < 1 || dtDay > 31) return false; // 小月31天校验 if ([4,6,9,11].includes(dtMonth) && dtDay === 31) return false; // 二月特殊处理 if (dtMonth === 2) { // 可选:两位年份转四位,比如99→1999,05→2005 // const fullYear = dtYear + (dtYear > 50 ? 1900 : 2000); // const isleap = (fullYear % 4 === 0 && (fullYear % 100 !== 0 || fullYear % 400 === 0)); const isleap = (dtYear % 4 === 0 && (dtYear % 100 !== 0 || dtYear % 400 === 0)); if (dtDay > 29 || (dtDay === 29 && !isleap)) return false; } return true; }
方案2:修正原代码的索引逻辑
如果要保留原正则结构,只需调整索引计算:
function isdateField1(currVal) { if (currVal === '') return false; var rxDatePattern = /^(\d{1,2})(-)(?:|(jan)|(feb)|(mar)|(apr)|(may)|(jun)|(jul)|(aug)|(sep)|(oct)|(nov)|(dec))(-)(\d{2})$/i; var dtArray = currVal.match(rxDatePattern); if (!dtArray) return false; var dtDay = parseInt(dtArray[1]); var dtMonth = parseInt(dtArray[3]); // 修正年份索引为16 var dtYear = parseInt(dtArray[16]); if (isNaN(dtMonth)) { // 从分组3(jan)开始循环,到分组14(dec)结束 for (var i = 3; i <= 14; i++) { if (dtArray[i]) { // 分组3对应1月,所以用i-2计算月份 dtMonth = i - 2; break; } } } if (dtMonth < 1 || dtMonth > 12) return false; else if (dtDay < 1 || dtDay > 31) return false; else if ((dtMonth == 4 || dtMonth == 6 || dtMonth == 9 || dtMonth == 11) && dtDay == 31) return false; else if (dtMonth == 2) { var isleap = (dtYear % 4 == 0 && (dtYear % 100 != 0 || dtYear % 400 == 0)); if (dtDay > 29 || (dtDay == 29 && !isleap)) return false; } return true; }
内容的提问来源于stack exchange,提问作者Zooch84
相关产品推荐
相关产品推荐

