計算「年月日 → 年內天序數」是日期處理的基礎操作。本文實現基於閏年判斷宏與雙行累加天數表的 O(1) 查表算法,代碼簡潔、無分支循環、適合嵌入式環境。
#include#include // 閏年判斷宏:標準格里曆規則 #define IS_LEAP(y) (((y)%4==0 && (y)%100!=0) || (y)%400==0) // 累加天數表:[是否閏年][月份] -> 該月之前的總天數 // 索引 0 不用,1=1月,12=12月,13=全年總天數(用於校驗) static const int g_day_before_month[2][14] = { // 平年 {0, 0, 31, 59, 90, 120, 151, // 1-6 月前累計 181, 212, 243, 273, 304, 334, // 7-12 月前累計 365}, // 全年天數 // 閏年 {0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366} }; // 計算年內天序數 (1-based: 1月1日 = 1) int day_of_year(int year, int month, int day) { if (month < 1 || month > 12) return -1; int leap = IS_LEAP(year); int days_before = g_day_before_month[leap][month]; // 當月天數校驗 int dim = g_day_before_month[leap][month+1] - days_before; if (day < 1 || day > dim) return -1; return days_before + day; } int main() { int y, m, d; printf("請輸入日期 (YYYY-MM-DD): "); if (scanf("%d-%d-%d", &y, &m, &d) != 3) return 1; int doy = day_of_year(y, m, d); if (doy == -1) { printf("日期非法\n"); } else { printf("%04d-%02d-%02d 是 %d 年的第 %d 天\n", y, m, d, y, doy); } return 0; }
請輸入日期 (YYYY-MM-DD): 2024-02-29 2024-02-29 是 2024 年的第 60 天 請輸入日期 (YYYY-MM-DD): 2023-12-31 2023-12-31 是 2023 年的第 365 天 請輸入日期 (YYYY-MM-DD): 2020-01-01 2020-01-01 是 2020 年的第 1 天
| 方案 | 時間複雜度 | 代碼量 | 分支預測 | 適用場景 |
|---|---|---|---|---|
| 查表法 (本文) | O(1) | 極小 | 無分支 | 嵌入式、高頻調用、裸機 |
| 循環累加 | O(month) | 小 | 有分支 | 教學演示、月份動態 |
| Zeller 公式變體 | O(1) | 中 | 無分支 | 日曆算法、週幾計算 |
// 當月天數
int days_in_month(int y, int m) {
if (m < 1 || m > 12) return 0;
int leap = IS_LEAP(y);
return g_day_before_month[leap][m+1] - g_day_before_month[leap][m];
}
// 判斷日期合法性
int is_valid_date(int y, int m, int d) {
return day_of_year(y, m, d) != -1;
}
// 日期加減天數 (簡化版,不跨年)
int add_days(int y, int m, int d, int delta) {
int doy = day_of_year(y, m, d);
if (doy == -1) return -1;
int leap = IS_LEAP(y);
int max_day = g_day_before_month[leap][13];
int new_doy = doy + delta;
if (new_doy < 1 || new_doy > max_day) return -1; // 需跨年處理
// 反查表得月日...
return 0;
}
Linux 內核 kernel/time/time.c 中的 leap_year() 與 days_in_month() 採用相同閏年宏與查表思想,證明了該算法的工業級可靠性。
查表法以「空間換時間」將日期計算降為 O(1) 純整數運算,無循環、無分支、無函數調用開銷,是資源受限環境下日期處理的最優選。