判断闰年是计算二月天数的核心逻辑:平年28天,闰年29天;正确规则为能被4整除但不能被100整除,或能被400整除;c++20可用std::chrono::year_month_day直接获取二月最后一天,否则需手写is_leap函数并校验输入。

判断闰年是计算二月天数的核心逻辑
二月天数只取决于是否闰年:平年28天,闰年29天。C++标准库没有直接提供“某年是否闰年”的函数,必须自己实现判断逻辑。常见错误是只用 year % 4 == 0,这会把1900、2100等世纪年份误判为闰年。
正确规则是:能被4整除但不能被100整除,或能被400整除。对应代码就是:
bool is_leap(int year) {
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
- 注意:年份为负数(如公元前)时,C++取模行为依赖实现,建议限定输入范围(如1–9999)
-
std::chrono::year(C++20)支持y.is_leap(),但需编译器启用C++20且年份在[−32767, 32767]内
用 std::chrono::year_month_day 获取二月最后一天(C++20)
C++20引入了日历类型,可绕过手动判断,直接查出该年2月的最后一天日期,再提取日数值。这是最语义清晰、不易出错的方式,但要求编译器支持C++20。
int feb_days_cpp20(int year) {
std::chrono::year y{year};
auto feb_last = std::chrono::year_month_day{
y / std::chrono::February / std::chrono::last
};
return static_cast<int>(feb_last.day());
}</int>
- 传入非法年份(如0或负数)可能抛出
std::domain_error - 不依赖本地时区,纯日历计算,结果确定
- 比手写闰年逻辑多一次构造和转换,性能差异可忽略
兼容 C++11/14/17 的简洁实现
如果项目不能升级到C++20,一个健壮、无依赖、一行核心逻辑的函数就足够:
int feb_days(int year) {
return is_leap(year) ? 29 : 28;
}
这里 is_leap 就是前面定义的函数。关键点在于:
- 不要用
time_t+mktime构造2月29日再检查——跨平台行为不一致,且对无效日期(如1900-02-29)可能静默失败 - 避免硬编码年份范围表(如查表法),维护成本高且无法覆盖所有年份
- 如果需频繁调用,可加
constexpr(C++14起)让编译期计算:constexpr bool is_leap(int y)
容易被忽略的边界情况
实际使用中,真正出问题的往往不是逻辑本身,而是输入和上下文:
- 用户输入的
year是字符串,未做数字校验,导致stoi抛异常或截断(如"2024abc"→2024) - 从数据库读取年份字段为
NULL或空值,直接传入函数引发未定义行为 - 调用方假设返回值永远是28或29,但若传入0或负数且未校验,
is_leap可能返回意外结果(如C++中-100 % 4是 -0 还是 0 取决于实现)
真正要做的不是写个“正确”的函数,而是确保它接收到的是有效年份——校验应在调用前完成,而不是塞进 feb_days 里兜底处理。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











