Ruby中如何编写严格校验yyyy-mm-dd格式日期的可靠函数
Ruby 严格yyyy-mm-dd格式日期校验实现
原实现存在两个核心问题:
- 存在低级变量笔误:方法入参定义为
string,strptime调用时传入的是未定义的date变量,实际运行会直接抛出名称错误 DateTime.strptime默认采用宽松解析逻辑,不要求输入字符串和指定格式完全匹配,只要字符串内存在可解析的符合规则的片段、或者分段长度不符合要求时会自动截断解析,不会抛出异常,这就是错位分段字符串被误判为合法的根本原因。
可靠的校验需要同时满足三层校验规则,才能覆盖所有边缘场景:
- 第一层:正则做全字符串格式匹配,从字符串开头到结尾严格符合
4位年份-2位月份-2位日期的结构,不允许前后存在多余字符、分段长度不符的情况 - 第二层:调用日期解析方法做合法性校验,依赖标准库内置的闰年、大小月、合法月份区间规则做判断,避免手写规则出现遗漏
- 第三层:反向格式校验,将解析完成的日期对象重新按照
%Y-%m-%d格式转成字符串,和原始输入做全等比对,彻底堵上宽松解析的漏洞
可直接使用的实现代码如下:
require 'date' def validate_date?(input_str) # 正则全匹配过滤格式不符合的输入 return false unless input_str.match?(/\A\d{4}-\d{2}-\d{2}\z/) date_format = '%Y-%m-%d' parsed_date = DateTime.strptime(input_str, date_format) # 反向格式化校验,避免宽松解析误判 parsed_date.strftime(date_format) == input_str rescue ArgumentError false end
校验效果验证
所有边缘场景均可返回正确结果:
- 合法日期返回
true:- 闰年2月29日:
validate_date?('2024-02-29')=>true - 常规合法日期:
validate_date?('2022-05-20')=>true
- 闰年2月29日:
- 格式非法输入返回
false:- 顺序错误的日期:
validate_date?('20-05-2022')=>false - 分段长度错误:
validate_date?('202200-06-02')、validate_date?('2022-060-002')=>false - 前后带多余字符:
validate_date?(' 2022-06-02')、validate_date?('2022-06-02abc')=>false
- 顺序错误的日期:
- 日期值非法输入返回
false:- 平年2月29日:
validate_date?('2023-02-29')=>false - 不存在的月份:
validate_date?('2022-13-01')=>false - 小月31日:
validate_date?('2022-04-31')=>false
- 平年2月29日:
内容的提问来源于stack exchange,提问作者Navin Ojha
相关产品推荐
相关产品推荐

