最可靠方法是直接提取年份字段比较。c++中需根据日期类型(std::tm、c++20 std::chrono::year_month_day或date.h)正确获取年份:std::tm需加1900校正,c++20和date.h支持year()直接比较,且自动校验有效性。

直接提取年份比较最可靠
判断两个日期是否同一年,本质是比对它们的年份字段。C++ 中没有统一的“日期对象”,具体做法取决于你用的是哪种日期表示方式——std::tm、std::chrono::sys_days,还是第三方库如 date::year_month_day。核心原则:**不要手动解析字符串或做时间戳差值计算,避免跨年边界(如12月31日 vs 1月1日)导致误判**。
常见错误是用 time_t 相减再除以 365×24×3600,这在闰年、夏令时切换时必然出错;还有人把日期字符串按“-”分割取第一段,但没校验格式合法性,遇到 "2023/12/31" 就挂了。
用 std::tm 解析时注意 tm_year 偏移
std::tm 的 tm_year 是从 1900 年起算的,不是真实年份。比如 2023 年对应 tm_year == 123。直接比较前必须加 1900。
- 用
std::get_time解析字符串时,确保格式匹配(如"%Y-%m-%d"),否则tm_year可能为未定义值 - 解析失败后
ss.fail()为 true,此时不能读tm字段,否则行为未定义 - 即使解析成功,也要检查
tm.tm_year是否在合理范围(如0 ),防止溢出或异常输入
std::tm t1 = {}, t2 = {};
std::istringstream ss1("2023-06-15"), ss2("2023-12-25");
ss1 >> std::get_time(&t1, "%Y-%m-%d");
ss2 >> std::get_time(&t2, "%Y-%m-%d");
if (ss1.fail() || ss2.fail()) { /* 处理错误 */ }
bool same_year = (t1.tm_year + 1900) == (t2.tm_year + 1900);
用 C++20 std::chrono::year_month_day 更安全
C++20 引入了类型安全的日期操作,std::chrono::year_month_day 自带年份提取,无需手动偏移或校验范围,且构造失败会抛 std::runtime_error,比 std::tm 更易排查问题。
- 构造时自动验证日期有效性(如
2023-02-30会抛异常,而std::tm可能静默接受) -
y1.year()返回std::chrono::year类型,支持直接 == 比较,语义清晰 - 输入格式必须严格为
YYYY-MM-DD(ISO 格式),不支持斜杠或点分隔
using namespace std::chrono;
auto ymd1 = year_month_day{sys_days{year{2023}/month{6}/day{15}}};
auto ymd2 = year_month_day{sys_days{year{2023}/month{12}/day{25}}};
bool same_year = ymd1.year() == ymd2.year();
第三方库 date.h 的 date::year_month_day 用法几乎一致
如果你还在用 C++17 或更早版本,Howard Hinnant 的 date.h 是事实标准。它的 date::year_month_day API 和 C++20 几乎完全兼容,只是命名空间是 date 而非 std::chrono。
- 同样要求 ISO 格式字符串,可用
date::parse安全解析 - 解析失败返回
is_valid() == false,不会抛异常,需主动检查 - 和 C++20 一样,
y1.year() == y2.year()可直接比较,结果类型是date::year
date::year_month_day ymd1, ymd2;
std::istringstream ss1("2023-06-15"), ss2("2023-12-25");
ss1 >> date::parse("%Y-%m-%d", ymd1);
ss2 >> date::parse("%Y-%m-%d", ymd2);
if (!ymd1.ok() || !ymd2.ok()) { /* 处理无效日期 */ }
bool same_year = ymd1.year() == ymd2.year();
真正容易被忽略的是输入来源的多样性:用户输入、数据库字段、API 返回 JSON 字符串……每种来源都可能带空格、时区、非标准分隔符或非法值。别指望一次解析通吃,先标准化再进比较逻辑。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











