代碼中 29/2/2001 加一天變成 30/2/2001(非法日期),而 28/2/2001 正確變為 1/3/2001。
根因在閏年判斷條件:
if (year/4==0) // 錯誤:整除而非取模
2001 年:2001 % 4 = 1 → 平年,2月只有 28 天。
bool isLeapYear(int year) {
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
void Date::add_date() {
// 每月天數表(平年)
static const int daysInMonth[12] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
int maxDay = daysInMonth[month - 1];
// 2月閏年調整
if (month == 2 && isLeapYear(year)) {
maxDay = 29;
}
if (day < maxDay) {
day++;
} else {
day = 1;
if (month < 12) {
month++;
} else {
month = 1;
year++;
}
}
}
#include <iostream>
#include <stdexcept>
class Date {
public:
Date(int y = 1970, int m = 1, int d = 1) : year(y), month(m), day(d) {
if (!isValid()) throw std::invalid_argument("Invalid date");
}
void addDay() { /* 上述邏輯 */ }
void show() const {
std::cout << day << '/' << month << '/' << year << '\n';
}
private:
int year, month, day;
static bool isLeapYear(int y) {
return (y % 4 == 0 && y % 100 != 0) || (y % 400 == 0);
}
bool isValid() const {
if (month < 1 || month > 12) return false;
static const int days[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
int maxDay = days[month-1];
if (month == 2 && isLeapYear(year)) maxDay = 29;
return day >= 1 && day <= maxDay;
}
};
int main() {
Date d1(2001, 2, 28); d1.addDay(); d1.show(); // 1/3/2001
Date d2(2000, 2, 28); d2.addDay(); d2.show(); // 29/2/2000 (閏年)
Date d3(2000, 2, 29); d3.addDay(); d3.show(); // 1/3/2000
Date d4(2023, 12, 31); d4.addDay(); d4.show(); // 1/1/2024
return 0;
}
| 錯誤寫法 | 正確寫法 | 說明 |
|---|---|---|
year/4==0 | year%4==0 | 整除 vs 取模 |
| 硬編碼每月天數判斷 | 查表法 + 閏年調整 | 減少重複代碼,易維護 |
| 無輸入驗證 | 構造函數驗證合法性 | 防止非法日期對象創建 |
日期計算看似簡單,邊界條件極多(閏年、月末、年末、閏秒等),生產環境建議使用成熟庫(C++20
<chrono>、Howard Hinnant's date、Boost.Date_Time),避免重複造輪子引入 Bug。