日期格式驗證是表單處理的基本需求。本文提供三種實用的正則表達式方案:基礎格式檢查、嚴格邏輯驗證 (含月份天數與閏年)、歐式 DD/MM/YYYY 格式,並說明 PHP 實作注意事項。
僅檢查格式結構,不驗證日期邏輯合法性:
$pattern = '/^\d{4}-\d{1,2}-\d{1,2}$/'; $dates = ['2004-06-01', '2005-0x-10', '12-12-12', '2000-12-25 00:10:20', '2007-12-05']; foreach ($dates as $date) { if (preg_match($pattern, $date, $matches)) { echo "符合格式: $date => 年={$matches[0]}, 月={$matches[1]}, 日={$matches[2]}<br>"; } else { echo "<b>不符合格式: $date</b><br>"; } }
精確匹配合法日期,包含:
$strictPattern = '/^( (?: # 非閏年 \d{4}-(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01]) | \d{4}-(?:0[469]|11)-(?:0[1-9]|[12]\d|30) | \d{4}-02-(?:0[1-9]|1\d|2[0-8]) ) | (?: # 閏年 2 月 29 日 (?:\d{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29 ) )$/x'; // 測試 $testDates = [ '2023-02-28', '2023-02-29', // 平年 '2024-02-28', '2024-02-29', // 閏年 '2023-04-31', '2023-04-30', // 小月 '2023-13-01', '2023-00-10' // 非法月份 ]; foreach ($testDates as $d) { echo "$d: " . (preg_match($strictPattern, $d) ? '✓ 合法' : '✗ 不合法') . "<br>"; }
支援單雙位數日/月,同樣包含閏年邏輯:
$euPattern = '/^( (?: \d{4}[-/](?:0[13578]|1[02])[-/](?:0[1-9]|[12]\d|3[01]) | \d{4}[-/](?:0[469]|11)[-/](?:0[1-9]|[12]\d|30) | \d{4}[-/]02[-/](?:0[1-9]|1\d|2[0-8]) ) | (?: (?:\d{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)[-/]02[-/]29 ) )$/x';
正則表達式雖強大但難維護。PHP 提供更可靠的內建驗證:
// 1. checkdate() - 最簡單可靠 function isValidDate($year, $month, $day) { return checkdate((int)$month, (int)$day, (int)$year); } // 2. DateTime::createFromFormat() - 解析並驗證字串 function validateDateString($dateStr, $format = 'Y-m-d') { $dt = DateTime::createFromFormat($format, $dateStr); return $dt && $dt->format($format) === $dateStr; } // 3. 結合 strtotime() (需注意鬆散解析) function looseValidate($dateStr) { $ts = strtotime($dateStr); return $ts !== false && date('Y-m-d', $ts) === $dateStr; } // 測試 var_dump(isValidDate(2024, 2, 29)); // true (閏年) var_dump(isValidDate(2023, 2, 29)); // false var_dump(validateDateString('2024-02-29')); // true var_dump(validateDateString('2024-13-01')); // false
| 方法 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| 正則嚴格版 | 單一表達式、無函式呼叫 | 極難閱讀維護、效能較差 | 純前端 JS、資料庫 CHECK 條件 |
| checkdate() | 核心優化、語義清晰、正確處理閏年 | 需先拆分年月日 | PHP 後端驗證首選 |
| DateTime::createFromFormat | 支援多種格式、自動標準化 | 物件建立開銷略大 | 解析使用者輸入字串 |
瀏覽器原生支援 type="date" 輸入框自動驗證,或使用 checkdate 邏輯移植:
function isValidDateJS(year, month, day) { const d = new Date(year, month - 1, day); return d.getFullYear() === year && d.getMonth() === month - 1 && d.getDate() === day; } // HTML5 原生驗證 // <input type="date" required> // 瀏覽器自動檢查格式與合法性
日期驗證首選 PHP 內建 checkdate() 或 DateTime::createFromFormat(),正確、可讀、可維護。正則表達式適合無法使用程式語言函式的場景 (如資料庫約束、前端純 JS 環境)。嚴格版正則雖複雜但展示了閏年邏輯的完整實現,理解其原理有助於深入掌握日期運算規則。