日期校验 / 时间校验正则表达式解析

日期校验 / 时间校验正则表达式解析

0 结论

以下为常用的日期格式校验表达式

0.1 日期格式校验

以下日期校验可满足“四年一闰,百年不闰,四百年再闰”

  • yyyyMMdd
^(?:(?!0000)[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]|1[0-9]|2[0-8]))|(?:(((\d{2})(0[48]|[2468][048]|[13579][26])|(([02468][048])|([13579][26]))00))0229))$
  • yyyy-MM-dd
^(?:(?!0000)[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]|\-1[0-9]|\-2[0-8]))|(?:(((\d{2})(0[48]|[2468][048]|[13579][26])|(([02468][048])|([13579][26]))00))\-02\-29))$

0.2 时间格式校验

  • hhmmss

12 小时制,范围为 000000 - 115959

^(?!120000)(?:0[0-9]|1[12])(?:[0-5][0-9]){2}$

24 小时制,范围为 000000 - 235959

^(?!240000)(?:[01][0-9]|2[1-4])(?:[0-5][0-9]){2}$
  • hh:mm:ss

12 小时制,范围为 00:00:00 - 11:59:59

^(?!12\:00\:00)(?:0[0-9]|1[12])(?:\:[0-5][0-9]){2}$

24 小时制,范围为 00:00:00 - 23:59:59

^(?!24\:00\:00)(?:[01][0-9]|2[1-4])(?:\:[0-5][0-9]){2}$

0.3 使用方式

String uncheckedStr = "2023-12-12";
final String REGEX_PATTERN = "^(?:(?!0000)[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]|\-1[0-9]|\-2[0-8]))|(?:(((\d{2})(0[48]|[2468][048]|[13579][26])|(([02468][048])|([13579][26]))00))\-02\-29))$";
if (!Pattern.matches(REGEX_PATTERN, uncheckedStr)) {
    throw new BusinessException(ErrorCodeEnum.INVALID_TIME_PATTERN);
}

1 日期校验正则表达式解析

yyyyMMdd 为例解析日期校验正则表达式组装过程

  1. 匹配前四位年份,匹配范围为 0001-9999 ,使用 (?!) 排除 0000 ,获得 yyyy 部分的校验正则表达式
(?!0000)[0-9]{4}
  1. 由于月份与日期关联存在多种可能,因此采用模式匹配
1. 31 天的月份 01 03 05 07 08 10 12
(?:0[13578]|1[02])          匹配月份
(?:0[1-9]|[12][0-9]|3[01])  匹配日期 01 - 31 

2. 30 天的月份 04 06 09 11
(?:0[469]|11)               匹配月份
(?:0[1-9]|[12][0-9]|30)     匹配日期 01 - 30

3. 02 月存在闰月的问题,且条件较为复杂,因此先匹配 01 - 28 的日期范围
02                          匹配月份
(?:0[1-9]|1[0-9]|2[0-8])    匹配日期 01 - 28
  1. 使用 | 组装匹配模式,多个模式使用 (?:MODELA|MODELB|MODELC) 的方式进行组合,此处组合匹配模式后获得 mmdd 部分的校验正则表达式
匹配 MMdd 的表达式
(?:(?: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]|1[0-9]|2[0-8]))
   |--            31 天的月份日期              --|--          30 天的月份日期         --|--     28 天的月份日期    --|
  1. 拼接第 1 步和第 3 步的匹配模式以组装基本的 yyyyMMdd 模式,该模式下不考虑闰年,因此将第 2 步的二月的日期匹配范围改到了 29,该模式无法辨认 1900-02-29 的非闰年情形
不考虑闰年的简易模式(二月的日期匹配范围改到了29,以下模式能正常使用)
^(?!0000)[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]|1[0-9]|2[0-9]))$
  1. 进一步处理闰年年份
1. 非百年的年份处理较为简单,枚举 4 的倍数且不为 100 的倍数的年份
((\d{2})(0[48]|[2468][048]|[13579][26])

2. 百年年份保留 400 的倍数
(([02468][048])|([13579][26]))00)
  1. 拼接模式以匹配闰年日期 yyyy0229
(((\d{2})(0[48]|[2468][048]|[13579][26])|(([02468][048])|([13579][26]))00))0229
|--          非百年                    --|--        百年(保留400年)      --|
  1. 结合第 3 步和第 6 步的结果组装最终的匹配模式,该模式可以满足 四年一闰,百年不闰,四百年再闰 的需求
^(?:(?!0000)[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]|1[0-9]|2[0-8]))|(?:(((\d{2})(0[48]|[2468][048]|[13579][26])|(([02468][048])|([13579][26]))00))0229))$
  • 9
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值