闰年判断的核心逻辑是严格遵循格里高利历规则:(year % 4 == 0 && year % 100 != 0) || (year % 400 == 0),该公式仅适用于1582年10月15日之后的公历日期,c++20起可直接使用std::chrono::year::is_leap()。

闰年判断的核心逻辑是什么
C++ 里没有内置的“高精度闰年判断”函数,std::chrono 也不直接暴露年份是否闰年的接口。所谓“高精度”,其实是指严格遵循格里高利历(Gregorian calendar)规则,而非简单套用“能被4整除就是闰年”的粗略说法——后者在1582年历法改革前不适用,且对世纪年份(如1900、2000)会出错。
真正可靠的判断必须满足:
- 能被4整除,但不能被100整除;或者
- 能被400整除
(year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)注意:这个公式只对公历(格里高利历)有效,且默认你处理的是1582年10月15日之后的日期。若需支持儒略历(如俄罗斯、希腊部分历史时期),得额外分支处理,但绝大多数现代系统不需要。
用 std::chrono::year 判断(C++20起)
C++20 引入了 std::chrono::year 类型,它自带 is_leap() 成员函数,内部已按格里高利历实现,是目前最简洁、最不易出错的方式:
#include <chrono>
#include <iostream><p>int main() {
std::chrono::year y{2000};
std::cout </p>
<p>关键点:</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/gongju/2823" title="C++14"><img
src="https://img.php.cn/upload/manual/001/431/639/6ac8b33c327c4749.png" alt="C++14" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="overflowclass">C++14</a>
<p class="overflowclass">C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。</p>
</div>
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
<ul>
<li>仅限 C++20 及以上标准,老项目编译可能失败</li>
<li>
<code>std::chrono::year</code> 构造函数接受 <code>int</code>,但不校验范围(如传 -1000 也能构造,<code>is_leap()</code> 仍按格里高利历算)</li>
<li>它不处理历法切换点(1582-10-04 儒略历 → 1582-10-15 格里高利历),即默认全部按格里高利历回溯计算——这和大多数编程库一致,但与真实历史有偏差</li>
</ul>
<h3>手动实现时容易踩的坑</h3>
<p>自己写判断逻辑看似简单,但实际容易翻车:</p>
<ul>
<li>用 <code>year / 4 * 4 == year</code> 替代 <code>year % 4 == 0</code>:对负数年份(如公元前1年记为0或-1)结果不同,且无必要</li>
<li>忽略整数除法截断:比如误写 <code>year % 400 == 0 && year % 100 == 0</code>,导致 2000 被判为非闰年(逻辑颠倒)</li>
<li>把 <code>year % 100 == 0</code> 当作“世纪年”充分条件:1900 是世纪年但不是闰年,2000 才是</li>
<li>未处理 <code>year</code> 为负值的情况:C++ 中负数取模结果依赖实现(C++11起标准化为向0截断),但 <code>%</code> 对负年份仍可安全用于闰年判断——因为闰年定义本身基于数学整除性,而 <code>a % b == 0</code> 在 <code>b > 0</code> 时,等价于 <code>b</code> 整除 <code>a</code>(无论 <code>a</code> 正负)</li>
</ul>
<p>所以最稳妥的手动写法仍是:</p>
<pre class="brush:php;toolbar:false;">bool is_leap(int year) {
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
如果要解析字符串日期再判断呢
常见场景是拿到 "2024-02-29" 这样的字符串,想验证它是否合法(即年份是否闰年、2月是否有29日)。这时不能只看年份,还要结合月份和日:
- 先用
std::get_time或strptime(POSIX)或第三方库(如 date.h)解析年/月/日 - 再调用闰年判断逻辑,检查是否为2月且日 > 28 —— 若是,且年份非闰年,则非法
- 注意:2月30日、4月31日这类明显越界日期,闰年判断前就该被解析器拒绝,不必靠闰年逻辑兜底
例如用 date::parse(Howard Hinnant 的 date 库):
auto tp = date::sys_days{};
if (date::parse(ss, "%Y-%m-%d", tp)) {
auto y = date::year_month_day{tp}.year();
bool valid_feb29 = (y.month() == date::February && y.day() == date::day{29});
if (valid_feb29 && !y.year().is_leap()) { /* 错误 */ }
}
真正麻烦的不是闰年判断本身,而是把日期字符串、时区、历法、解析错误统一处理好。单纯“判断闰年”这件事,一行表达式就够了。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










