驗證字串是否符合日期格式是表單驗證、資料匯入常見需求。本文整理常用日期格式的正則表達式,並提供 DateTime.TryParse 等更穩健的替代方案比較。
\b(?\d{2,4})/(?\d{1,2})/(?\d{1,2})\b
\b:字邊界(?...) :具名擷取群組\d{2,4}:2-4 位數字 (年)\d{1,2}:1-2 位數字 (月/日)
\b(?\d{2,4})-(?\d{1,2})-(?\d{1,2})\b
\b(?\d{2,4})年(?\d{1,2})月(?\d{1,2})日\b
using System;
using System.Text.RegularExpressions;
public static class DateValidator
{
// 預編譯正則表達式提升效能
private static readonly Regex SlashFormat = new Regex(
@"\b(?\d{2,4})/(?\d{1,2})/(?\d{1,2})\b",
RegexOptions.Compiled);
private static readonly Regex DashFormat = new Regex(
@"\b(?\d{2,4})-(?\d{1,2})-(?\d{1,2})\b",
RegexOptions.Compiled);
private static readonly Regex ChineseFormat = new Regex(
@"\b(?\d{2,4})年(?\d{1,2})月(?\d{1,2})日\b",
RegexOptions.Compiled);
///
/// 檢查字串是否符合任一支援的日期格式
///
public static bool IsDateFormat(string input)
{
if (string.IsNullOrWhiteSpace(input))
return false;
return SlashFormat.IsMatch(input)
|| DashFormat.IsMatch(input)
|| ChineseFormat.IsMatch(input);
}
///
/// 嘗試解析日期,回傳 DateTime 與格式類型
///
public static bool TryParseDate(string input, out DateTime date, out string format)
{
date = default;
format = null;
if (string.IsNullOrWhiteSpace(input))
return false;
var match = SlashFormat.Match(input);
if (match.Success && TryCreateDate(match, out date))
{
format = "yyyy/MM/dd";
return true;
}
match = DashFormat.Match(input);
if (match.Success && TryCreateDate(match, out date))
{
format = "yyyy-MM-dd";
return true;
}
match = ChineseFormat.Match(input);
if (match.Success && TryCreateDate(match, out date))
{
format = "yyyy年MM月dd日";
return true;
}
return false;
}
private static bool TryCreateDate(Match match, out DateTime date)
{
date = default;
try
{
int year = int.Parse(match.Groups["year"].Value);
int month = int.Parse(match.Groups["month"].Value);
int day = int.Parse(match.Groups["day"].Value);
// 處理兩位數年份 (假設 00-29 為 2000-2029,30-99 為 1930-1999)
if (year < 100)
year += year < 30 ? 2000 : 1900;
date = new DateTime(year, month, day);
return true;
}
catch
{
return false;
}
}
}
正則表達式僅驗證格式,不保證日期真實存在 (如 2023/02/30)。完整驗證需結合 DateTime.TryParse:
public static bool IsValidDate(string input, out DateTime date)
{
date = default;
// 先用正則快速篩選格式
if (!IsDateFormat(input))
return false;
// 再用 TryParse 驗證實際有效性
// 需指定格式避免文化特性差異
string[] formats = { "yyyy/MM/dd", "yy/MM/dd", "yyyy-MM-dd", "yy-MM-dd",
"yyyy年MM月dd日", "yy年MM月dd日" };
return DateTime.TryParseExact(input, formats,
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.None, out date);
}
using System.Diagnostics;
public void Benchmark()
{
string[] testCases = { "2023/12/25", "2023-12-25", "2023年12月25日",
"invalid", "2023/13/45", "2023/02/30" };
int iterations = 100000;
var sw = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++)
{
foreach (var tc in testCases)
DateValidator.IsDateFormat(tc);
}
Console.WriteLine($"正則驗證: {sw.ElapsedMilliseconds} ms");
sw.Restart();
for (int i = 0; i < iterations; i++)
{
foreach (var tc in testCases)
DateTime.TryParse(tc, out _);
}
Console.WriteLine($"TryParse: {sw.ElapsedMilliseconds} ms");
sw.Restart();
for (int i = 0; i < iterations; i++)
{
foreach (var tc in testCases)
DateValidator.IsValidDate(tc, out _);
}
Console.WriteLine($"完整驗證: {sw.ElapsedMilliseconds} ms");
}
/*
典型結果:
正則驗證: 45 ms (最快,但不檢查日期合法性)
TryParse: 120 ms (較慢,但自動處理多種格式)
完整驗證: 180 ms (最慢,但最準確)
*/
| 格式名稱 | 正則模式 | 範例 | 適用場景 |
|---|---|---|---|
| ISO 8601 | ^\d{4}-\d{2}-\d{2}$ | 2023-12-25 | API、資料庫、國際標準 |
| 斜線分隔 | ^\d{2,4}/\d{1,2}/\d{1,2}$ | 2023/12/25 | 中文習慣、舊系統 |
| 連字號分隔 | ^\d{2,4}-\d{1,2}-\d{1,2}$ | 2023-12-25 | 美式、系統日誌 |
| 中文完整 | ^\d{2,4}年\d{1,2}月\d{1,2}日$ | 2023年12月25日 | 中文文件、報表 |
| 含時間 | ^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$ | 2023-12-25 14:30:00 | 日誌、審計追蹤 |
| Unix Timestamp | ^\d{10,13}$ | 1703485800 | 系統整合、快取 |
DateTime.TryParseExact 指定格式陣列CultureInfo.InvariantCulture 避免伺服器設定影響
public static class ExtendedDateValidator
{
private static readonly string[] SupportedFormats =
{
"yyyy/MM/dd", "yy/MM/dd",
"yyyy-MM-dd", "yy-MM-dd",
"yyyy.MM.dd", "yy.MM.dd",
"yyyy年MM月dd日", "yy年MM月dd日",
"yyyy/MM/dd HH:mm", "yyyy-MM-dd HH:mm:ss",
"yyyy/MM/dd HH:mm:ss", "yyyy-MM-ddTHH:mm:ss"
};
public static bool TryParseFlexible(string input, out DateTime date)
{
return DateTime.TryParseExact(input, SupportedFormats,
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.AllowWhiteSpaces, out date);
}
}
日期格式驗證有三層次:正則表達式驗證格式 (快但不準)、TryParse 驗證可解析性 (準但慢)、完整驗證包含邏輯合法性 (最準但最慢)。實務上建議根據場景選擇:使用者介面即時驗證用正則,資料處理管線用 TryParseExact 指定格式。預編譯正則、指定文化特性、處理兩位數年份歧義是關鍵細節。