日期时间校验正则的写法
正则能把日期时间限制在「月份 1 到 12、日期 1 到 31、时 0 到 23、分秒 0 到 59」这一层,但无法表达大小月与闰年:形如 2 月 30 日、4 月 31 日仍会通过。因此标准分工是正则为输入格式把关,日期库为语义把关。接口与日志字段格式相对固定,正则在这一层的价值是提前挡住肉眼可见的错误。
基本信息
| 日期形状 | 年四位、月两位、日两位,月份写作 0[1-9]|1[0-2],日期写作 0[1-9]|[12]\d|3[01] |
|---|---|
| 时间形状 | 时可写 [01]\d|2[0-3],分秒写作 [0-5]\d |
| ISO 8601 | 日期与时间之间用字母 T 或空格,小数秒可选,时区可写 Z 或加偏移 |
| 正则做不到 | 大小月天数、闰年 2 月 29 日、时区实际有效性 |
| 推荐流程 | 先按允许的格式做结构校验,再用日期库构造对象并统一时区 |
典型使用场景
- 接口参数校验:先挡掉格式错误的字符串,再交给业务逻辑处理
- 日志时间戳提取:从固定格式的日志里取出时间字段并归一化
- 表单输入提示:在提交前给出即时反馈,减少无效请求
- 批量导入预检:把格式异常的记录集中列出,避免整批回滚
- 数据清洗:把斜杠写法与连字符写法统一成一种,便于排序与比较
常用写法与二次校验
常用写法与二次校验
# 日期形状:限制月份与日期的数字范围,但不校验大小月
^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])$
# 时间形状:时限制到 23,分秒限制到 59
^(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d)?$
# ISO 8601 风格的整体校验:日期与时间用 T 或空格分隔,时区可选
^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d{1,6})?(?:Z|[+-]\d{2}:\d{2})?$
# 语义校验交给日期库:大小月、闰年、时区偏移都由它判断
datetime.datetime.fromisoformat(s) # 格式与语义一起校验字段限制与语义检查
| 字段 | 正则限制范围 | 需代码补做的判断 |
|---|---|---|
| 月 | 01 到 12 | 无 |
| 日 | 01 到 31 | 按月份与年份判断是否存在该日 |
| 时 | 00 到 23 | 是否需要允许 24 点表示法 |
| 分与秒 | 00 到 59 | 是否需要处理闰秒 60 |
| 时区偏移 | 形如加号或减号加两小时两分 | 偏移是否在合理范围、是否与地区匹配 |
带时区与不带时区的时间不能直接比较大小:排序前统一换算到同一时区,否则跨时区的记录顺序会出错,这类问题在小样本上不易发现。
闰年规则是能被 4 整除且不能被 100 整除,或能被 400 整除;这层逻辑写在正则里几乎不可读,也不便测试,交给日期库更合适。