首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

C語言計算某年某月某日是當年的第幾天:閏年判斷與累加表查表法

     編輯:關於C

計算「年月日 → 年內天序數」是日期處理的基礎操作。本文實現基於閏年判斷宏與雙行累加天數表的 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 內核同源實現參考

Linux 內核 kernel/time/time.c 中的 leap_year() 與 days_in_month() 採用相同閏年宏與查表思想,證明了該算法的工業級可靠性。

查表法以「空間換時間」將日期計算降為 O(1) 純整數運算,無循環、無分支、無函數調用開銷,是資源受限環境下日期處理的最優選。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved