CodeGym /課程 /C# SELF /日期與時間的格式化與解析

日期與時間的格式化與解析

C# SELF
等級 15 , 課堂 3
開放

1. 日期格式化

如果你覺得 2025-06-19T17:30:00 這種輸出很潮,試著給你阿嬤或會計看這種格式。他們大概會比較喜歡簡單一點的:19.06.2025 17:30。英文同事則會期待 06/19/2025 5:30 PM。DevOps 跟機器人最愛 2025-06-19T17:30:00Z。所以一個 DateTime 在程式記憶體裡,螢幕上可以有十幾種不同格式。

反過來也很常見:使用者在輸入框裡打日期("19.06.2025"),我們要能正確解析成 C# 物件,而且不能搞混哪個是天哪個是月。自動化、整合、報表——到處都需要正確解讀文字日期。

基本格式化

C# 讓你可以用 DateTimeDateOnlyTimeOnlyDateTimeOffset 這些日期/時間物件的 .ToString() 方法轉成字串:


DateTime now = DateTime.Now;
Console.WriteLine(now.ToString()); // 輸出:19.06.2025 17:30:25
日期和時間的基本格式化

如果你呼叫 .ToString() 不帶參數——會用系統目前文化的格式(像德國 Windows 一種,美國又是另一種)。

標準格式字串

你可以直接指定輸出格式,用所謂的標準日期和時間格式字串:

格式 說明 範例輸出
"d"
簡短日期 19.06.2025
"D"
完整日期 2025年6月19日
"f"
完整日期 + 簡短時間 2025年6月19日 17:30
"F"
完整日期 + 完整時間 2025年6月19日 17:30:25
"g"
簡短日期和時間 19.06.2025 17:30
"G"
簡短日期 + 完整時間 19.06.2025 17:30:25
"t"
簡短時間 17:30
"T"
完整時間 17:30:25
"M"/"m"
月和日 6月19日
"Y"/"y"
年和月 2025年6月
"O"/"o"
ISO 8601(round-trip) 2025-06-19T17:30:25.0000000

Console.WriteLine(now.ToString("d")); // 19.06.2025
Console.WriteLine(now.ToString("F")); // 2025年6月19日 17:30:25
Console.WriteLine(now.ToString("O")); // 2025-06-19T17:30:25.0000000

自訂(客製)模板

如果你想要更特別的格式,可以用自己的模板:

符號 意思
yyyy 年,4 位數
yy 年,2 位數
MM 月,2 位數
MMMM 月份名稱
dd 日,2 位數
d 日,1-2 位數
HH 小時(24小時制)
mm 分鐘
ss
tt AM/PM

Console.WriteLine(now.ToString("yyyy-MM-dd HH:mm")); // 2025-06-19 17:30
Console.WriteLine(now.ToString("dd.MM.yyyy"));       // 19.06.2025
Console.WriteLine(now.ToString("dddd, MMMM d"));     // 星期三, 6月 19

格式化的文化差異

如果你想要用其他國家或語言的風格顯示結果,可以用 ToString(string, IFormatProvider) 這個 overload:


var enUS = new System.Globalization.CultureInfo("en-US");
Console.WriteLine(now.ToString("D", enUS)); // June 19, 2025
  • 如果你硬指定模板像 "MM/dd/yyyy",不管什麼文化都會得到 "06/19/2025"
  • 但如果只用 "d""D"——格式就會跟文化有關!

格式化時要注意的重點

處理日期格式化時,要搞清楚標準格式和自訂格式的差別。標準格式(像 "d""F""G")會自動根據系統文化調整,很適合 UI,但系統間資料交換時可能會出問題。自訂格式讓你完全掌控輸出,但要自己細細設定。

特別要注意 "O"(或 "o")這種格式——這就是所謂的 "round-trip" 格式,保證你把日期轉成字串再轉回來會一模一樣。這在序列化或網路傳輸時超重要。

2. 日期和時間的解析:怎麼從字串拿到物件

最簡單的解析:DateTime.Parse

DateTime.Parse——這個方法會根據系統文化去解析日期字串。


string input = "19.06.2025";
DateTime parsed = DateTime.Parse(input);
Console.WriteLine(parsed); // 19.06.2025 00:00:00

如果字串不正確——程式會直接丟例外(沒人能保證安全!)。

指定文化


string input = "06/19/2025";
var enUS = new System.Globalization.CultureInfo("en-US");
DateTime dt = DateTime.Parse(input, enUS);
Console.WriteLine(dt); // 19.06.2025 00:00:00

安全解析:TryParse


string input = "錯誤的日期";
bool ok = DateTime.TryParse(input, out DateTime safeDate);
if (!ok)
    Console.WriteLine("錯誤:無法解析日期!");

強制指定格式:ParseExact 和 TryParseExact


var culture = System.Globalization.CultureInfo.InvariantCulture;
string dateStr = "2025-06-19";

DateTime d = DateTime.ParseExact(dateStr, "yyyy-MM-dd", culture);
Console.WriteLine(d); // 19.06.2025 00:00:00

bool parsedOk = DateTime.TryParseExact(
    "19.06.2025",
    "dd.MM.yyyy",
    System.Globalization.CultureInfo.InvariantCulture,
    System.Globalization.DateTimeStyles.None,
    out DateTime myDate);

常見格式表

字串 格式 最終物件
"2025-06-19" "yyyy-MM-dd" 2025年6月19日
"19.06.2025" "dd.MM.yyyy" 2025年6月19日
"06/19/2025" "MM/dd/yyyy" 2025年6月19日
"2025-06-19T14:15:16" "s" 2025年6月19日 14:15:16

使用 DateTimeStyles

解析時你還可以用 DateTimeStyles 這個參數來調整行為。這個 enum 讓你設定解析器怎麼解讀輸入資料。像 DateTimeStyles.AssumeUniversal 會讓解析器把時間當成 UTC(如果沒明確寫偏移),DateTimeStyles.AllowWhiteSpaces 會忽略多餘空白。這些設定在處理外部資料來源時超有用,因為格式可能很難預測。

3. DateOnlyTimeOnly 的格式化與解析

新的 DateOnlyTimeOnly 型別現在很常用來存日期/時間,不會有多餘細節。

格式化


DateOnly birthday = new DateOnly(2000, 6, 19);
Console.WriteLine(birthday.ToString("dd MMMM yyyy")); // 2000年6月19日

解析


var d = DateOnly.ParseExact("19.06.2000", "dd.MM.yyyy");
Console.WriteLine(d.Day); // 19

TimeOnly 的方法也一樣(只是模板只跟時/分/秒有關):

TimeOnly t = TimeOnly.ParseExact("23:59", "HH:mm");
Console.WriteLine(t.Hour); // 23

DateOnly 和 TimeOnly 的優點

DateOnlyTimeOnly 取代 DateTime 有幾個很重要的好處。第一,語意更清楚——如果你只要日期(像生日),DateOnly 就很明確。第二,可以避免 DateTime 可能遇到的時區問題。第三,這些型別在記憶體和資料庫裡佔的空間更小。

考慮時區的格式化與解析

如果你要存有偏移資訊的時間——就用 DateTimeOffset。這對國際化、分散式系統特別重要。所有格式化和解析方法都一樣,只是現在可以處理偏移:


DateTimeOffset meeting = new DateTimeOffset(2025, 6, 19, 17, 30, 0, TimeSpan.FromHours(3));
Console.WriteLine(meeting.ToString("o")); // 2025-06-19T17:30:00.0000000+03:00

string input = "2025-06-19T17:30:00+03:00";
var parsedOffset = DateTimeOffset.Parse(input);
Console.WriteLine(parsedOffset.Offset); // 03:00:00

4. 實用建議與常見錯誤

一個常見陷阱——解析國際格式時把「日」跟「月」搞混。像 "01/02/2025" 在美國是 1 月 2 日,在大多數歐洲國家卻是 2 月 1 日(驚喜!)。

也常常會忘記文化的影響:如果你的應用程式跑在德國的伺服器上,但用戶來自不同國家,從資料庫拿出來的日期格式在每台伺服器上可能會被解讀成不一樣。

很多人會犯的錯——在 log 或交換檔案時用 .ToString() 沒指定文化/格式:結果可能在換作業系統或不同 Windows 使用者下就變了。

日期處理建議

  • 內部儲存和資料交換時,永遠用 invariant culture(CultureInfo.InvariantCulture)或明確指定格式。
  • UI 上用戶端就用用戶的文化,或讓他自己選想要的格式。
  • 跟 API 和資料庫打交道時,優先用 ISO 8601 格式,這是國際標準。
  • 永遠驗證輸入資料:檢查日期是否存在、範圍和合理性。

處理不同資料來源

跟外部系統整合時,常常會遇到各種格式的日期。有些系統會用 Unix timestamp(從 1970 年 1 月 1 日起的秒數),有些則用本地格式的字串。一定要事先約定好資料交換格式,並且每次都檢查解析結果。

也要記得,有些格式可能很模糊。像 "12/13/2025" 很明顯是 2025 年 12 月 13 日,但 "12/11/2025" 可能是 12 月 11 日,也可能是 11 月 12 日,這就看文化設定了。這種情況最好用不會搞混的格式,或明確指定解析文化。

留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION