在無法直接使用 DateTime 結構的環境中(如嵌入式系統、數據庫存儲過程、跨語言移植),需要純算法計算給定日期對應的星期幾。本文介紹經典的基姆拉爾森公式並對比 .NET 內置方法。
將 1、2 月視作上一年的 13、14 月,通過數學公式計算星期索引:
W = (d + 2*m + 3*(m+1)/5 + y + y/4 - y/100 + y/400) % 7 + 1
d:日期m:月份(1、2 月按 13、14 處理)y:年份(1、2 月年份 -1)W:1=周一 ... 7=周日public static string CalculateWeekDay(int year, int month, int day)
{
// 參數驗證
if (month < 1 || month > 12 || day < 1 || day > 31)
throw new ArgumentException("無效日期參數");
// 基姆拉爾森公式核心
if (month == 1 || month == 2)
{
month += 12;
year--;
}
int week = (day + 2 * month + 3 * (month + 1) / 5 + year + year / 4 - year / 100 + year / 400) % 7 + 1;
return week switch
{
1 => "星期一",
2 => "星期二",
3 => "星期三",
4 => "星期四",
5 => "星期五",
6 => "星期六",
7 => "星期日",
_ => throw new InvalidOperationException("算法異常")
};
}
// WinForms 測試調用
private void btnCalculate_Click(object sender, EventArgs e)
{
try
{
int y = int.Parse(txtYear.Text);
int m = int.Parse(txtMonth.Text);
int d = int.Parse(txtDay.Text);
lblResult.Text = CalculateWeekDay(y, m, d);
}
catch (Exception ex)
{
MessageBox.Show($"輸入錯誤: {ex.Message}");
}
}
| 日期 | 公式結果 | DateTime 驗證 | 備註 |
|---|---|---|---|
| 2024-01-01 | 星期一 | Monday | 元旦 |
| 2024-02-29 | 星期四 | Thursday | 閏年 |
| 2024-10-01 | 星期二 | Tuesday | 國慶 |
| 1900-01-01 | 星期一 | Monday | 非閏年世紀 |
| 2000-02-29 | 星期二 | Tuesday | 閏年世紀 |
測試結果:公式計算與 DateTime.DayOfWeek 完全一致(注意枚舉值 0=Sunday 需轉換)。
// 現代開發首選:一行代碼
DateTime dt = new DateTime(2024, 10, 1);
DayOfWeek dow = dt.DayOfWeek; // 枚舉值:Tuesday
// 轉中文顯示
string chineseWeek = dow switch
{
DayOfWeek.Monday => "星期一",
DayOfWeek.Tuesday => "星期二",
DayOfWeek.Wednesday => "星期三",
DayOfWeek.Thursday => "星期四",
DayOfWeek.Friday => "星期五",
DayOfWeek.Saturday => "星期六",
DayOfWeek.Sunday => "星期日",
_ => ""
};
| 維度 | 基姆拉爾森公式 | DateTime.DayOfWeek |
|---|---|---|
| 適用場景 | 無框架環境、SQL 函數、跨語言移植、教學演示 | 常規 .NET 應用開發 |
| 代碼複雜度 | 需自行實現、驗證、維護 | 零代碼、框架保證正確性 |
| 性能 | 極快(純整數運算) | 極快(內部優化) |
| 邊界處理 | 需手動處理曆法切換(格里曆/儒略曆) | 自動處理 1753 年後格里曆 |
| 本地化 | 需自行映射語言 | 支持 CultureInfo 本地化 |
DateTime.DayOfWeek,不可重複造輪子System.DayOfWeek 擴展方法統一中文顯示邏輯💡 避坑指南:網上流傳的許多示例代碼存在「1、2 月未調整年份」、「模 7 後映射錯誤」等問題,本文代碼經 1900-2100 年全量驗證,可放心使用。