南非身份证号出生日期校验异常问题及代码审查请求
南非身份证号出生日期校验代码问题排查与修复
问题根源
你的代码存在几个关键错误,导致二月天数超过29时仍返回true:
- 无效的条件分支赋值:第一个
if块中,当检测到无效日期(比如二月day>29)时,仅写了isDOBValid;,没有将其赋值为false。而else分支会将isDOBValid设为true,后续的正则判断又会覆盖这个结果。 - 冗余且错误的正则判断逻辑:第二个
if-else块完全多余,而且只要日期格式符合正则(比如2024-02-30格式合法但实际无效),就会强制将isDOBValid设为true,直接忽略了之前的天数校验。 - 字符串比较隐患:
month和day是从身份证号截取的字符串,直接用>比较可能出现非预期结果,转为数字比较更严谨。 - 缺失闰年判断:原代码允许二月最多29天,但未区分平年和闰年,平年二月最多28天,这也是一个逻辑漏洞。
修复后的代码
function checkDateOfBirth(idNumber) { // 截取日期部分并转为数字 const yearStr = idNumber.substring(0, 2); const month = parseInt(idNumber.substring(2, 4), 10); const day = parseInt(idNumber.substring(4, 6), 10); // 确定完整年份(南非身份证号两位年份规则:小于当前年份-2000则归为20xx,否则19xx) const currentYear = new Date().getFullYear(); const cutOff = currentYear - 2000; const fullYear = parseInt(yearStr, 10) > cutOff ? 1900 + parseInt(yearStr, 10) : 2000 + parseInt(yearStr, 10); // 初始化校验结果为false let isDOBValid = false; // 基础范围校验 if (month < 1 || month > 12 || day < 1 || day > 31) { return isDOBValid; } // 处理小月(4、6、9、11月最多30天) if ([4, 6, 9, 11].includes(month) && day > 30) { return isDOBValid; } // 处理二月,区分闰年 if (month === 2) { // 闰年判断规则:能被4整除但不能被100整除,或者能被400整除 const isLeapYear = (fullYear % 4 === 0 && fullYear % 100 !== 0) || (fullYear % 400 === 0); if ((isLeapYear && day > 29) || (!isLeapYear && day > 28)) { return isDOBValid; } } // 所有校验通过,设为true isDOBValid = true; return isDOBValid; }
修复说明
- 将
month和day转为数字,避免字符串比较的潜在问题。 - 移除冗余的正则判断,改用实际的日期逻辑校验,确保格式和有效性都正确。
- 新增闰年判断,严格校验二月的天数(平年28天,闰年29天)。
- 简化分支逻辑,一旦检测到无效条件直接返回
false,避免后续逻辑覆盖结果。 - 优化年份计算逻辑,直接转为完整数字年份,便于闰年判断。
内容的提问来源于stack exchange,提问作者PalesaDev
相关产品推荐
相关产品推荐

