輸入兩個日期,計算它們相差多少天。沿用日期結構體,核心難點:跨年處理、閏年正確統計。原代碼同樣存在閏年判斷 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;
}
y/4 - y/100 + y/4001 到 y 年間閏年數 = 能被 4 整除 - 能被 100 整除 + 能被 400 整除。O(1) 替代循環,極其高效。
(year-1)*365:平年基礎天數;+ 閏年數:每個閏年多 1 天;+ 當年月日累積:查表 + day;+ 當年閏年補償:month>2 時 +1。計算「在此之前的完整年份天數」。如 2024 年,之前完整年份是 1~2023 年,共 2023 年。
| 日期1 | 日期2 | 預期差值 | 原代碼結果 | 說明 |
|---|---|---|---|---|
| 2023-12-30 | 2024-01-02 | 3 | 362 (錯) | 跨年 |
| 2024-02-28 | 2024-03-01 | 2 | 2 (對) | 閏年內 |
| 2000-01-01 | 2000-12-31 | 365 | 365 (對) | 閏年全年 |
| 1900-01-01 | 1900-12-31 | 364 | 364 (對) | 平年世紀年 |
| 2023-01-01 | 2023-01-01 | 0 | 0 | 同一天 |
日期差計算暴露了「局部思維(各自年間天數相減)無法解決全局問題(跨年)」的典型誤區。關鍵收穫:
y/4 - y/100 + y/400 是 O(1) 神器;CUM_DAYS 消除循環,代碼簡潔高效;long long 避免年份較大時溢出(int 32位約 ±21億天 ≈ ±580萬年,通常夠用但 ll 更安心)。