DateTime.Now:本地時間(含時區)DateTime.UtcNow:UTC 時間(儲存/傳輸首選)DateTime.Today:當地日期 00:00:00DayOfWeek:列舉(Sunday=0 ~ Saturday=6)DayOfYear:今年第幾天所有公式以 DateTime dt = DateTime.Today 為基準,僅保留日期部分,避免時間誤差。
// 本週起始(週日)
var weekStart = dt.AddDays(-(int)dt.DayOfWeek);
// 本週結束(週六)
var weekEnd = weekStart.AddDays(6);
// 上週起始/結束
var lastWeekStart = weekStart.AddDays(-7);
var lastWeekEnd = weekStart.AddDays(-1);
// 下週起始/結束
var nextWeekStart = weekStart.AddDays(7);
var nextWeekEnd = nextWeekStart.AddDays(6);
// 本月第一天
var monthStart = new DateTime(dt.Year, dt.Month, 1);
// 本月最後一天
var monthEnd = monthStart.AddMonths(1).AddDays(-1);
// 上月
var lastMonthStart = monthStart.AddMonths(-1);
var lastMonthEnd = monthStart.AddDays(-1);
// 下月
var nextMonthStart = monthStart.AddMonths(1);
var nextMonthEnd = nextMonthStart.AddMonths(1).AddDays(-1);
// 本季第一天
int quarter = (dt.Month - 1) / 3 + 1;
var quarterStart = new DateTime(dt.Year, (quarter - 1) * 3 + 1, 1);
// 本季最後一天
var quarterEnd = quarterStart.AddMonths(3).AddDays(-1);
// 上季
var lastQuarterStart = quarterStart.AddMonths(-3);
var lastQuarterEnd = quarterStart.AddDays(-1);
// 下季
var nextQuarterStart = quarterStart.AddMonths(3);
var nextQuarterEnd = nextQuarterStart.AddMonths(3).AddDays(-1);
var yearStart = new DateTime(dt.Year, 1, 1);
var yearEnd = new DateTime(dt.Year, 12, 31);
var lastYearStart = yearStart.AddYears(-1);
var lastYearEnd = yearStart.AddDays(-1);
var nextYearStart = yearStart.AddYears(1);
var nextYearEnd = yearStart.AddYears(2).AddDays(-1);
| 格式字串 | 輸出範例 | 用途 |
|---|---|---|
yyyy-MM-dd | 2024-03-15 | 標準日期(資料庫、API) |
yyyy-MM-01 | 2024-03-01 | 月首日技巧 |
yyyy-01-01 | 2024-01-01 | 年首日技巧 |
HH:mm:ss | 14:30:05 | 純時間 |
yyyyMMddHHmmss | 20240315143005 | 檔案名稱、流水號 |
ddd / dddd | 五 / 星期五 | 星期顯示 |
string[] weeks = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
string today = weeks[(int)DateTime.Today.DayOfWeek]; // "星期五"
var now = DateTime.Now;
now.AddDays(7); // 7 天後
now.AddDays(-7); // 7 天前
now.AddMonths(1); // 1 月後(自動處理月末)
now.AddYears(-1); // 1 年前
// 錯誤:字串按字元序比較,"2024-12-01" < "2024-2-01"
if (dateStr1 > dateStr2) { ... }
DateTime d1 = DateTime.Parse("2024-03-15");
DateTime d2 = DateTime.Parse("2024-03-20");
if (d1 < d2) { ... } // 早於
if (d1 == d2) { ... } // 同一天
if (d1.Date == d2.Date) { ... } // 忽略時間比較日期
// 計算差異
TimeSpan diff = d2 - d1;
int days = diff.Days; // 5 天
double hours = diff.TotalHours; // 120 小時
public bool IsNew(DateTime publishDate)
{
// 使用 Date 比較,忽略時間部分
return DateTime.Today <= publishDate.Date.AddDays(3);
}
// 或使用 UTC 避免時區問題
public bool IsNewUtc(DateTime publishDateUtc)
{
return DateTime.UtcNow.Date <= publishDateUtc.Date.AddDays(3);
}
| 場景 | 風險 | 對策 |
|---|---|---|
| 資料庫儲存 | 本地時間跨時區混亂 | 統一儲存 UTC (DateTime.UtcNow) |
| JSON 序列化 | 預設輸出本地時間無時區資訊 | 用 DateTimeOffset 或設定 JsonSerializerOptions |
| 跨時區使用者 | 顯示錯誤日期 | 前端負責轉換,後端只提供 UTC |
| 夏令時間切換 | 同一天出現 2 次或 0 次某小時 | 用 TimeZoneInfo.ConvertTime 處理 |
// 純日期,無時間、無時區
DateOnly today = DateOnly.FromDateTime(DateTime.Today);
DateOnly expiry = today.AddMonths(12);
// 純時間
TimeOnly openTime = new TimeOnly(9, 0);
TimeOnly closeTime = new TimeOnly(18, 0);
// 組合
DateTime dt = today.ToDateTime(openTime); // 2024-03-15 09:00:00
日期邊界計算核心原則:先對齊到大單位起始(年/月/季/週首日),再用 AddDays/AddMonths 微調。避免手算天數、避免字串拼湊、善用 DateOnly 表達純日期語意。掌握這些模式,報表查詢、排程觸發、業務週期判斷都能得心應手。