兩種常見周定義
| 定義 | 規則 | 適用場景 |
| ISO 8601 (國際標準) |
周一為每周第一天;包含第一個周四的周為第 1 周 |
歐洲、數據交換、.NET 內建 Calendar.GetWeekOfYear |
| 美式/中文習慣 (周日/周一為首日,1月1日所在周為第1周) |
1月1日所在周為第 1 周,不足 7 天也算 |
美國、中國通用業務邏輯 |
.NET 內建實現 (ISO 8601)
using System.Globalization;
public int GetIsoWeekOfYear(DateTime date) {
CultureInfo ci = CultureInfo.CurrentCulture; // 或 CultureInfo.InvariantCulture
Calendar cal = ci.Calendar;
CalendarWeekRule rule = CalendarWeekRule.FirstFourDayWeek; // ISO 規則
DayOfWeek firstDay = DayOfWeek.Monday;
return cal.GetWeekOfYear(date, rule, firstDay);
}
自定義:1月1日所在周為第 1 周 (周一為首日)
public int GetCustomWeekOfYear(DateTime date, DayOfWeek firstDayOfWeek = DayOfWeek.Monday) {
// 1. 計算當年 1 月 1 日是星期幾
DateTime jan1 = new DateTime(date.Year, 1, 1);
int daysOffset = (int)firstDayOfWeek - (int)jan1.DayOfWeek;
if (daysOffset > 0) daysOffset -= 7; // 向前推到本周第一天
DateTime firstWeekStart = jan1.AddDays(daysOffset); // 第 1 周的周一
// 2. 如果日期在 firstWeekStart 之前,屬於上一年最後一周
if (date < firstWeekStart) {
return GetCustomWeekOfYear(new DateTime(date.Year - 1, 12, 31), firstDayOfWeek);
}
// 3. 計算差值天數 / 7
int diffDays = (date - firstWeekStart).Days;
return diffDays / 7 + 1;
}
簡化版 (不跨年處理,僅當年內)
public int GetSimpleWeekOfYear(DateTime date) {
// 假設周一為首日,1月1日所在周為第1周
DateTime jan1 = new DateTime(date.Year, 1, 1);
int daysSinceJan1 = date.DayOfYear - 1; // 0-based
int jan1WeekDay = (int)jan1.DayOfWeek; // 0=Sun ... 6=Sat
// 轉換為周一=0
int jan1MonBased = (jan1WeekDay + 6) % 7;
return (daysSinceJan1 + jan1MonBased) / 7 + 1;
}
測試用例
// 2024-01-01 是周一
GetIsoWeekOfYear(new DateTime(2024,1,1)) // 1
GetCustomWeekOfYear(new DateTime(2024,1,1)) // 1
GetSimpleWeekOfYear(new DateTime(2024,1,1)) // 1
// 2024-12-31 是周二
GetIsoWeekOfYear(new DateTime(2024,12,31)) // 1 (ISO 第 1 周屬於 2025)
GetCustomWeekOfYear(new DateTime(2024,12,31)) // 53
GetSimpleWeekOfYear(new DateTime(2024,12,31)) // 53
選擇建議
- 對接外部系統/標準報表 → **ISO 8601** (
Calendar.GetWeekOfYear)。
- 內部業務報表/中文習慣 → **自定義 1月1日所在周為第1周** (上方
GetCustomWeekOfYear)。
- 簡單統計、不跨年 → **簡化版
GetSimpleWeekOfYear**。