日期格式驗證看似簡單,實則暗藏玄機:大小月天數不同、閏年 2 月 29 日判斷邏輯複雜。網上流傳一個「特牛」的正則表達式,能在單一模式中完整覆蓋 YYYY-MM-DD 格式的所有邊界條件,甚至延伸支援時間部分。本文拆解其結構,助你理解並靈活應用。
^(
((1[6-9]|[2-9]\d)\d{2})-(0?[13578]|1[02])-(0?[1-9]|[12]\d|3[01]) | # 31天月份
((1[6-9]|[2-9]\d)\d{2})-(0?[13456789]|1[012])-(0?[1-9]|[12]\d|30) | # 30天月份
((1[6-9]|[2-9]\d)\d{2})-0?2-(0?[1-9]|1\d|2[0-8]) | # 2月平年1-28日
(((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-0?2-29)
)$
(1[6-9]|[2-9]\d)\d{2} → 1600-9999 年。0?[13578]|1[02](1,3,5,7,8,10,12),日期 0?[1-9]|[12]\d|3[01]。0?[13456789]|1[012](排除 2 月),日期 0?[1-9]|[12]\d|30。0?2 月份,日期 0?[1-9]|1\d|2[0-8](1-28 日)。(0[48]|[2468][048]|[13579][26])。(16|[2468][048]|[3579][26])00。^(
...以上日期部分...
)
(20|21|22|23|[0-1]?\d):[0-5]?\d:[0-5]?\d$
20|21|22|23|[0-1]?\d → 0-23(允許單數字或雙數字)。[0-5]?\d → 0-59。new Date(str) 配合比對年月日,或使用成熟庫(Moment.js, date-fns, Luxon)。這個「特牛」正則展示了正則表達式處理複雜業務邏輯的極致能力,但也提醒我們:能用正則不代表都該用正則。理解其原理有助於閱讀遺留代碼,新項目優先選擇可維護性更強的專用日期庫。