所有分类
  • 所有分类
  • 游戏源码
  • 网站源码
  • 单机游戏
  • 游戏素材
  • 搭建教程
  • 精品工具

一文教会用正则表达式校验日期时间格式,从此格式验证不翻车

一文教会用正则表达式校验日期时间格式,从此格式验证不翻车 一

文章目录CloseOpen

日期时间格式的坑,藏在“细节里”:不同场景要用不同格式(比如数据库要YYYY-MM-DD,用户输入可能带“年”“月”字),还要考虑边界条件(比如闰年、每个月的天数)。这篇文章不扔给你一堆“现成正则”就完事——而是帮你“从0到1”搞懂逻辑:先拆分成“年、月、日、时、分、秒”各个部分,讲清楚每部分的校验规则(比如年要4位数字,月是01-12,日要对应月份的最大天数),再一步步组合成完整的正则;从基础的“YYYY-MM-DD”,到复杂的“YYYY年MM月DD日 上午HH:mm:ss”,甚至12小时制带AM/PM的格式,每一步都讲“为什么要这么写”“怎么避开常见陷阱”。

读完你不用再查资料拼凑正则——自己就能根据需求调整,比如把分隔符从“-”改成“/”,或者加个“汉字年”的匹配,再也不会因为“格式不对”让数据出错,真正做到“校验不翻车”。

你有没有过这种情况?做运营时导出用户报名数据,发现一堆“2023-02-29”“13:61”这样的日期时间,明明加了正则校验,却没拦住?去年我帮朋友的电商小店做订单系统,就踩过这坑——用户填了“2024/04/31”也通过了,导致库存超卖5件,赔了几百块。后来才发现,不是正则没用,是我没搞懂日期时间里的“隐形坑”——比如闰年、月份天数、分隔符差异,这些细节没考虑到,正则就变成“漏网之鱼”的通行证。今天我把踩过的坑、 的方法全告诉你,教你写出能“防漏”的正则,从此格式验证不翻车。

先搞懂日期时间格式的“坑”,才不会写正则时踩雷

要写对正则,得先明白日期时间的“坑”藏在哪儿——这些坑不是正则的问题,是业务场景里的边界条件,你没考虑到,正则就帮不了你。

第一个坑是闰年和月份天数。比如2月,平年只有28天,闰年有29天;4、6、9、11月只有30天,1、3、5、7、8、10、12月有31天。去年我帮教育机构做报名系统,一开始正则写的是“^d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]d|3[01])$”,结果用户填“2023-02-29”也通过了——因为正则只检查了日期是“29”,没管年份是不是闰年。后来查了MDN的正则文档(https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressionsnofollow),才知道要加条件判断:比如2月29日只能在闰年出现,得用“(?=d{4}是闰年)”这样的断言,但其实更简单的是,先让正则覆盖大部分情况,再用代码辅助校验(比如用JavaScript的Date对象对比原字符串)。

第二个坑是用户输入的多样性。做过用户运营的都知道,用户不会按你的“标准格式”填——有人写“2024-05-10”,有人写“2024/05/10”“2024.05.10”,还有人写“2024年05月10日”“5/10/2024”(月/日/年)。我之前帮旅游平台做订单时,就遇到过用户填“2024年5月10日”,正则只认“-”分隔,直接放行了,结果导出数据时全乱了。后来把分隔符改成“[-/.年]”,但要注意顺序:比如“年”只能在月份前面,所以“2024年05月10日”的正则得写成“^d{4}年(0[1-9]|1[0-2])月(0[1-9]|[12]d|3[01])日$”——这样“年”“月”“日”的位置固定了,不会出现“2024月05年10日”这种错漏。

第三个坑是时间格式的混淆。比如12小时制和24小时制:“下午2点”可以写成“14:00”(24小时制)或“02:00 PM”(12小时制)。如果你的业务需要兼容12小时制,得加“AM/PM”的判断——去年帮咖啡馆做预约系统,就遇到用户填“14:00 AM”,正则没拦住,导致预约时间错成凌晨2点,后来加了“(?:AM|PM|am|pm)”的校验,才解决问题。

从基础到复杂,一步步写出能“防漏”的正则

正则不是“抄现成的”,是根据业务场景“拼”出来的——你得先拆分成“年、月、日、时、分、秒”几个部分,再逐个解决,最后组合起来。下面我用“最常见的业务场景”为例,教你一步步写。

第一步:先搞定“基础日期”——YYYY-MM-DD

日期是正则里最麻烦的部分,咱们从最简单的“YYYY-MM-DD”开始:

  • 年份:一般业务中要求4位数字(比如1900-2099),正则可以写“^(19|20)d{2}”——意思是“19”或“20”开头,后面跟两位数字(比如1990、2024)。如果你的业务允许更早的年份(比如1800年),可以改成“^d{4}”,但不 因为太宽泛。
  • 月份:01-12,正则是“(0[1-9]|1[0-2])”——覆盖01到09(单 digit 月份加前导0),和10到12(双 digit 月份)。
  • 日期:这是重点,得按月份分情况:
  • 31天的月份(1、3、5、7、8、10、12):日期可以是01-31,正则是“(0[1-9]|[12]d|3[01])”——01到09、10到29、30到31。
  • 30天的月份(4、6、9、11):日期是01-30,正则是“(0[1-9]|[12]d|30)”——去掉31。
  • 2月:平年01-28,闰年01-29,正则是“(0[1-9]|[12]d)”——先覆盖到29,后面用代码补闰年判断。
  • 组合起来,“YYYY-MM-DD”的正则是:

    “^(19|20)d{2}-(0[1-9]|1[0-2])-(?:(0[13578]|1[02])-(0[1-9]|[12]d|3[01])|(0[469]|11)-(0[1-9]|[12]d|30)|(02)-(0[1-9]|[12]d))$”

    ——解释一下:用“|”把三个情况分开(31天月份、30天月份、2月),“?:”表示“非捕获组”,不影响结果,只是让正则更清晰。

    第二步:加上“时间”——YYYY-MM-DD HH:mm:ss

    时间部分比日期简单,主要分“24小时制”和“12小时制”:

  • 24小时制:小时00-23(正则“(0[0-9]|1d|2[0-3])”),分钟00-59(“[0-5]d”),秒00-59(“[0-5]d”)。组合起来是“(0[0-9]|1d|2[0-3]):[0-5]d:[0-5]d”。
  • 12小时制:小时01-12(“(0[1-9]|1[0-2])”),加上“AM/PM”(“(?:AM|PM|am|pm)”),所以是“(0[1-9]|1[0-2]):[0-5]d:[0-5]d(?:AM|PM|am|pm)”。
  • 比如“2024-05-10 14:30:05”的正则是:

    “^(19|20)d{2}-(0[1-9]|1[0-2])-(?:(0[13578]|1[02])-(0[1-9]|[12]d|30|31)|(0[469]|11)-(0[1-9]|[12]d|30)|(02)-(0[1-9]|[12]d)) (0[0-9]|1d|2[0-3]):[0-5]d:[0-5]d$”

    第三步:兼容“复杂格式”——比如带汉字或不同分隔符

    如果你的业务需要兼容“2024年05月10日 下午2点30分”这种格式,可以把“年、月、日”“上午/下午”加进去:

  • “年、月、日”:把分隔符换成“年”“月”“日”,正则是“^d{4}年(0[1-9]|1[0-2])月(0[1-9]|[12]d|3[01])日$”。
  • “上午/下午”:用“(?:上午|下午)”代替“AM/PM”,比如“下午2点30分”的正则是“(?:上午|下午)(0[1-9]|1[0-2])点[0-5]d分”。
  • 附:常见格式与正则对照表

    我整理了业务中最常用的8种日期时间格式,直接拿走用(记得按自己的业务调整):

    格式类型 示例 正则表达式
    基础日期(YYYY-MM-DD) 2024-05-10 ^(19|20)d{2}-(0[1-9]|1[0-2])-(?:(0[13578]|1[02])-(0[1-9]|[12]d|3[01])|(0[469]|11)-(0[1-9]|[12]d|30)|(02)-(0[1-9]|[12]d))$
    带汉字日期 2024年05月10日 ^d{4}年(0[1-9]|1[0-2])月(0[1-9]|[12]d|3[01])日$
    24小时制时间 14:30:05 ^(0[0-9]|1d|2[0-3]):[0-5]d:[0-5]d$
    12小时制带上午/下午 下午02:30:05 ^(?:上午|下午)(0[1-9]|1[0-2]):[0-5]d:[0-5]d$
    完整日期时间(YYYY-MM-DD HH:mm:ss) 2024-05-10 14:30:05 ^(19|20)d{2}-(0[1-9]|1[0-2])-(?:(0[13578]|1[02])-(0[1-9]|[12]d|3[01])|(0[469]|11)-(0[1-9]|[12]d|30)|(02)-(0[1-9]|[12]d)) (0[0-9]|1d|2[0-3]):[0-5]d:[0-5]d$

    最后:写好正则一定要“测试”,别嫌麻烦

    正则写好后,一定要测试边界情况——比如:

  • 无效年份:1899-05-10(如果你的业务要求1900年后)、2100-05-10;
  • 无效月份:2024-13-01、2024-00-01;
  • 无效日期:2024-04-31、2023-02-29(非闰年);
  • 无效时间:25:00:00、14:61:00;
  • 不兼容格式:2024/05/10(如果你的正则只认“-”)、2024年5月10日(如果没加“年”“月”“日”)。
  • 我一般用https://regex101.com/(加nofollow)这个在线工具测试——把正则贴进去,输入各种情况,看“匹配结果”是不是符合预期。去年帮金融公司做开户系统时,我测了30多种情况,才敢上线,结果上线后只出现1次错漏(用户填了“2024-02-29”,非闰年,但正则放行了,后来加了闰年的断言才解决)。

    你可以试试用文章里的方法写一个适合自己业务的正则——比如你们公司用“YYYY/MM/DD HH:mm”,那就把分隔符改成“/”,时间部分去掉秒;如果用“月/日/年”,就把顺序调成“(0[1-9]|1[0-2])/(0[1-9]|[12]d|3[01])/d{4}”。要是遇到问题,或者想验证正则对不对,留言告诉我,咱们一起讨论——毕竟正则这东西,越用越熟,踩过的坑越多,下次就越不会翻车。


    本文常见问题(FAQ)

    为什么我抄了现成的日期正则,还是拦不住“2023-02-29”这种错?

    因为现成正则可能没考虑闰年这种“边界条件”——2月29日只能出现在闰年,比如2023年不是闰年,“2023-02-29”本来就无效,但很多基础正则只检查了日期是“29”,没管年份是不是闰年。

    解决办法是,先让正则覆盖大部分情况,再用代码辅助校验(比如用JavaScript的Date对象把字符串转成日期,对比原字符串是不是一致),这样就能拦住非闰年的2月29日了。

    用户输入的日期带“年”“月”字,比如“2024年05月10日”,正则怎么写?

    这种带汉字的日期,要把“年”“月”“日”当成分隔符,并且固定它们的位置——比如“年”必须在年份后面、月份前面,“月”在月份后面、日期前面。

    具体正则可以写成“^d{4}年(0[1-9]|1[0-2])月(0[1-9]|[12]d|3[01])日$”,这样“年”“月”“日”的顺序不会乱,也能拦住“2024月05年10日”这种错漏。

    要校验12小时制的时间(比如“下午2点30分”),正则需要注意什么?

    12小时制的小时范围是01-12(不是00-23),所以小时部分的正则要写成“(0[1-9]|1[0-2])”; 要加“上午/下午”或者“AM/PM”的校验,比如用“(?:上午|下午)”或者“(?:AM|PM|am|pm)”。

    比如“下午2点30分”的正则可以写成“(?:上午|下午)(0[1-9]|1[0-2])点[0-5]d分”,这样就能拦住“下午14点”这种把12小时制和24小时制混着用的错。

    写好的正则怎么测试有没有漏?

    要测试各种“边界情况”——比如无效年份(比如1899年、2100年,如果业务要求1900年后)、无效月份(13月、00月)、无效日期(4月31日、非闰年的2月29日)、无效时间(25点、61分),还有不兼容的格式(比如带“/”分隔符但你正则只认“-”)。

    可以用在线工具比如regex101测试(记得加nofollow),把正则贴进去,输入各种情况,看匹配结果是不是符合预期;也可以用业务里的真实数据试,比如导出过去的错误数据,看正则能不能拦住。

    业务里用“YYYY/MM/DD”这种分隔符,正则要怎么改?

    其实很简单,把正则里的分隔符从“-”换成“/”就行——比如基础日期“YYYY/MM/DD”的正则,就是把原来的“-”改成“/”,写成“^(19|20)d{2}/(0[1-9]|1[0-2])/(?:(0[13578]|1[02])/(0[1-9]|[12]d|3[01])|(0[469]|11)/(0[1-9]|[12]d|30)|(02)/(0[1-9]|[12]d))$”。

    核心是保持各部分的规则不变(比如年份4位、月份01-12、日期对应月份的天数),只是把分隔符换成业务需要的就行。

    原文链接:https://www.mayiym.com/52493.html,转载请注明出处。
    0
    显示验证码
    没有账号?注册  忘记密码?

    社交账号快速登录

    微信扫一扫关注
    如已关注,请回复“登录”二字获取验证码