首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

正則表達式匹配日期時間完全指南:從基礎格式到嚴格校驗

     編輯:Java 綜合教學

常見日期時間格式與正則對照表

格式範例正則表達式說明
2023-12-31^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$ISO 日期,基礎校驗
31/12/2023^(0[1-9]|[12]\d|3[01])/(0[1-9]|1[0-2])/\d{4}$英式日期
2023-12-31 23:59:59^\d{4}-\d{2}-\d{2} ([01]\d|2[0-3]):[0-5]\d:[0-5]\d$日期時間秒級
12:30 PM^(0?[1-9]|1[0-2]):[0-5]\d\s?(AM|PM)$12 小時制
23:59:59^([01]\d|2[0-3]):[0-5]\d:[0-5]\d$24 小時制含秒

進階:嚴格校驗(含閏年、大小月、平年 2 月 29 日邏輯)

純正則實現極其冗長(見文末附錄),工程實踐建議:正則做格式預檢 + 程式碼做邏輯校驗。

Java 實作:格式正則 + LocalDate 解析校驗

public class DateTimeValidator {
    // 常用格式正則(預編譯)
    private static final Pattern ISO_DATE = Pattern.compile("^\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])$");
    private static final Pattern ISO_DATETIME = Pattern.compile("^\\d{4}-\\d{2}-\\d{2} ([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d$");
    private static final Pattern CHINESE_DATE = Pattern.compile("^\\d{4}年(0?[1-9]|1[0-2])月(0?[1-9]|[12]\\d|3[01])日$");

    public static boolean isValidDate(String input, Pattern pattern, DateTimeFormatter formatter) {
        if (input == null) return false;
        if (!pattern.matcher(input).matches()) return false; // 格式快速失敗
        try {
            LocalDate.parse(input, formatter); // 語義校驗(閏年、月天數)
            return true;
        } catch (DateTimeParseException e) {
            return false;
        }
    }

    // 使用範例
    public static void main(String[] args) {
        System.out.println(isValidDate("2023-02-29", ISO_DATE, DateTimeFormatter.ISO_LOCAL_DATE)); // false
        System.out.println(isValidDate("2024-02-29", ISO_DATE, DateTimeFormatter.ISO_LOCAL_DATE)); // true
        System.out.println(isValidDate("2023-13-01", ISO_DATE, DateTimeFormatter.ISO_LOCAL_DATE)); // false (正則攔截)
    }
}

正則進階技巧

1. 命名捕獲組(Java 7+)

Pattern DATE_NAMED = Pattern.compile("^(?<year>\\d{4})-(?<month>0[1-9]|1[0-2])-(?<day>0[1-9]|[12]\\d|3[01])$");
Matcher m = DATE_NAMED.matcher("2023-12-31");
if (m.matches()) {
    int year = Integer.parseInt(m.group("year")); // 2023
    int month = Integer.parseInt(m.group("month")); // 12
}

2. 前瞻/後顧斷言實現「不捕獲分隔符」

// 匹配 2023-12-31 或 2023/12/31 或 2023.12.31,但分隔符必須一致
Pattern CONSISTENT_SEP = Pattern.compile("^\\d{4}([-/.])(0[1-9]|1[0-2])\\1(0[1-9]|[12]\\d|3[01])$");
// \\1 反向引用第一個分隔符

3. 預編譯與執行緒安全

  • Pattern 為不可變、執行緒安全,**靜態常量預編譯**,避免重複編譯開銷。
  • Matcher 非執行緒安全,**每次使用新建**或 ThreadLocal 復用。

附錄:純正則嚴格校驗日期(參考級,生產慎用)

^(
  # 31 天的月份
  (?:(?:31([-/.])(?:0?[13578]|1[02]))\1)
  |
  # 30 天的月份
  (?:(?:29|30)([-/.])(?:0?[13-9]|1[0-2])\2)
  |
  # 2 月
  (?:29([-/.])0?2\3(?:(?:(?:1[6-9]|[2-9]\d)(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))
  |
  # 1-28 號
  (?:0?[1-9]|1\d|2[0-8])([-/.])(?:0?[1-9]|1[0-2])\4
)
(?:1[6-9]|[2-9]\d)\d{2}$

警告:此類正則不可讀、難維護、效能差(回溯風險)。**生產環境請採用「正則預檢 + 時間庫解析」雙重校驗**。

最佳實踐總結

  1. 輸入端:前端用 `` 原生控制格式。
  2. 傳輸層:統一用 ISO 8601(yyyy-MM-dd / yyyy-MM-ddTHH:mm:ss),避免多格式混亂。
  3. 後端校驗:@Pattern(regexp=...) 註解做格式檢查 + LocalDate.parse() 做語義檢查。
  4. 資料庫存儲:用 DATE/DATETIME/TIMESTAMP 型別,勿存字串。
  5. 時區處理:全系統統一 UTC 存儲,展示層按用戶時區轉換。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved