<p>最简方式是用整除:季度 = (tm_mon + 1) / 3 + 1,年份 = tm_year + 1900;判断同季需联合年份与季度(如 year * 10 + quarter),避免仅比季度数或字符串拼接。</p>

提取年份和季度的最简方式
直接用整除运算算出季度,比写一堆 if 判断更可靠、也更易读。C++ 标准库没有原生季度类型,所以得自己拆解 tm 或 year_month_day 结构。
对任意日期(假设已转为 std::tm),季度 = (tm_mon + 1) / 3 + 1(注意:tm_mon 是 0–11)。年份直接取 tm_year + 1900。
-
tm_mon是 0 起始,3 月是 2,所以加 1 再整除 3 才能得到正确季度(1–4) - 别用
(tm_mon / 3) + 1—— 虽然结果一样,但语义模糊,容易误以为 0–2 是 Q1,实际 0–2 对应 1–3 月,没错;但加 1 再除更直白 - 如果用 C++20 的
std::chrono::year_month_day,先转成std::chrono::sys_days,再用std::chrono::floor<:chrono::days></:chrono::days>拆出year()和month(),逻辑一致
比较两个日期是否同季的判断逻辑
不能只比季度数,必须同时验证年份。Q4 2023 和 Q1 2024 的季度数都是 1,但显然不同季。
最安全写法是把「年+季」组合成一个可比较的整数,比如 year * 10 + quarter(2024×10+2=20242),再直接比大小。
立即学习“C++免费学习笔记(深入)”;
- 避免写成
year1 == year2 && quarter1 == quarter2—— 多一次比较,代码略啰嗦,且易漏掉年份检查 - 不要用字符串拼接(如
to_string(year)+to_string(quarter)),性能差,还可能因位数不齐导致字典序错误(如 "202" + "10" vs "2024" + "1") - 若日期来自不同来源(如数据库时间戳 vs 本地
time_t),务必确认时区已统一,否则tm_year可能偏差一年
常见错误:跨年 12 月和 1 月被误判为同季
典型陷阱是把 12 月(Q4)和次年 1 月(Q1)都当作“年底/年初”,然后凭经验认为它们“差不多”,结果在统计报表里把 2023-12-01 和 2024-01-15 当成同季。
这种错误往往出现在没显式提取年份、只看月份范围的代码里,比如:if (mon >= 1 && mon 就当 Q1 —— 完全忽略年份上下文。
- 所有季度判断必须绑定年份,脱离年份谈季度无意义
- 测试用例至少覆盖:2023-12-31 和 2024-01-01、2024-03-31 和 2024-04-01 这类边界日期
- 如果输入是字符串(如 "2024-03-15"),解析后务必校验
year是否在合理范围(如 1900–2100),防止stoi溢出或非法格式导致tm_year错乱
用 std::chrono(C++20)实现的简洁版本
如果你能用 C++20,std::chrono::year_month_day 配合 std::chrono::year 和 std::chrono::month 操作更类型安全,且自动处理闰年、月末等细节。
示例核心逻辑:
auto ymd1 = std::chrono::year_month_day{sys_days{date1}};
auto ymd2 = std::chrono::year_month_day{sys_days{date2}};
int q1 = (static_cast<int>(ymd1.month()) + 2) / 3;
int q2 = (static_cast<int>(ymd2.month()) + 2) / 3;
bool same_quarter = (ymd1.year() == ymd2.year()) && (q1 == q2);-
month()返回的是std::chrono::month类型,需转int才能算术运算 - 这里用
+2是为了适配 1–12 月:1→1, 2→1, 3→1, 4→2… 等价于(m+2)/3,比(m-1)/3+1少一次加减 - 注意
&&不是位与,是逻辑与;前面漏括号会导致优先级错误
季度计算本身很简单,真正容易出错的是年份对齐和边界日期的时区/历法处理。别跳过验证步骤。


















