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

C 語言結構體進階:兩日期天數差計算(修正閏年 Bug 並優化算法)

     編輯:關於C語言

問題描述

輸入兩個日期,計算它們相差多少天。沿用日期結構體,核心難點:跨年處理、閏年正確統計。原代碼同樣存在閏年判斷 Bug,且算法僅計算各自年間天數相減,無法處理跨年情況(如 2023-12-30 與 2024-01-02)。

原代碼缺陷分析


// Bug 1: checkyear 同前題,閏年/平年均返回 0
// Bug 2: 算法邏輯錯誤
for(i=0; i<2; i++) {
    // 計算各日期在「各自年」的第幾天
    sum_day[i] = 生日在該年的天數;
}
// 直接相減:sum_day[0] - sum_day[1]
// ❌ 2023-12-31 (第365天) - 2024-01-01 (第1天) = 364 天 → 錯誤!實際相差 1 天

正確算法:絕對天數法(儒略日 / 從基準日累積)

將日期轉換為「從某固定基準日(如 0000-01-01 或 1970-01-01)起的總天數」,相減即得差值。完美解決跨年、跨世紀、閏年所有問題。

完整工程級實現


#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

struct Date { int year, month, day; };

bool is_leap(int y) {
    return (y % 4 == 0 && y % 100 != 0) || (y % 400 == 0);
}

// 累積天數表:每月 1 日在平年中的「年前天數」
const int CUM_DAYS[13] = {
    0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
};

// 核心:日期轉絕對天數(從 0000-01-01 起算)
// 注意:年份 0 不存在歷史上,但作為數學基準無妨
long long date_to_absolute_days(struct Date d) {
    long long days = 0;

    // 1. 完整年份天數
    // 年份 1 到 year-1 的天數
    long long y = d.year - 1;
    days = y * 365 + y/4 - y/100 + y/400;  // 閏年數公式

    // 2. 當年內累積天數
    days += CUM_DAYS[d.month] + d.day;

    // 3. 閏年補償(當年是閏年且月份>2)
    if (is_leap(d.year) && d.month > 2) days++;

    return days;
}

long long days_between(struct Date d1, struct Date d2) {
    long long abs1 = date_to_absolute_days(d1);
    long long abs2 = date_to_absolute_days(d2);
    return llabs(abs1 - abs2);  // 絕對值差
}

int main() {
    struct Date d1, d2;
    printf("輸入第一個日期 (年 月 日): ");
    if (scanf("%d %d %d", &d1.year, &d1.month, &d1.day) != 3) return 1;
    printf("輸入第二個日期 (年 月 日): ");
    if (scanf("%d %d %d", &d2.year, &d2.month, &d2.day) != 3) return 1;

    long long diff = days_between(d1, d2);
    printf("兩日期相差 %lld 天\n", diff);

    // 額外輸出各自年間天數(原題要求)
    int doy1 = CUM_DAYS[d1.month] + d1.day + (is_leap(d1.year) && d1.month > 2);
    int doy2 = CUM_DAYS[d2.month] + d2.day + (is_leap(d2.year) && d2.month > 2);
    printf("日期1是 %d 年第 %d 天\n", d1.year, doy1);
    printf("日期2是 %d 年第 %d 天\n", d2.year, doy2);

    return 0;
}

算法核心解析

1. 閏年計數公式:y/4 - y/100 + y/400

1 到 y 年間閏年數 = 能被 4 整除 - 能被 100 整除 + 能被 400 整除。O(1) 替代循環,極其高效。

2. 絕對天數 = (year-1)年總天數 + 當年內天數

  • (year-1)*365:平年基礎天數;
  • + 閏年數:每個閏年多 1 天;
  • + 當年月日累積:查表 + day;
  • + 當年閏年補償:month>2 時 +1。

3. 為什麼用 year-1 而非 year?

計算「在此之前的完整年份天數」。如 2024 年,之前完整年份是 1~2023 年,共 2023 年。

測試驗證

日期1日期2預期差值原代碼結果說明
2023-12-302024-01-023362 (錯)跨年
2024-02-282024-03-0122 (對)閏年內
2000-01-012000-12-31365365 (對)閏年全年
1900-01-011900-12-31364364 (對)平年世紀年
2023-01-012023-01-0100同一天

總結

日期差計算暴露了「局部思維(各自年間天數相減)無法解決全局問題(跨年)」的典型誤區。關鍵收穫:

  • 絕對天數法:統一時間軸,相減即得差值,完美解決跨年/跨世紀/閏年;
  • 閏年計數公式 y/4 - y/100 + y/400 是 O(1) 神器;
  • 查表法 CUM_DAYS 消除循環,代碼簡潔高效;
  • long long 避免年份較大時溢出(int 32位約 ±21億天 ≈ ±580萬年,通常夠用但 ll 更安心)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved