判断季度第一天需检查month()是否为january、april、july或october且day()为1;年初第一天仅需month()为january且day()为1;注意输入类型转换陷阱和c++20日历类型的有效性校验。

判断日期是否为季度第一天:用 month() 和取模运算
C++ 标准库中没有直接的“季度”抽象,得靠月份推算。一年 12 个月,每 3 个月为一个季度,所以季度第一天只能是 1 月 1 日、4 月 1 日、7 月 1 日、10 月 1 日。关键看 month() 是否为 1、4、7 或 10,且 day() 为 1。
- 使用
std::chrono::year_month_day(C++20 起)可直接提取年、月、日 - 若用旧式
struct tm,注意tm_mon是从 0 开始的(即tm_mon == 0表示 1 月),需加 1 再判断 - 不要写
(m % 3 == 1)这类错误逻辑——因为 4 % 3 == 1,7 % 3 == 1,但 1 % 3 == 1 也成立,而 10 % 3 == 1 同样成立,看似巧但不可靠;更稳妥的是显式枚举或用(m - 1) / 3看整除结果是否变化
auto ymd = std::chrono::year_month_day{sys_days{tp}};
bool is_qtr_first = (ymd.month() == January || ymd.month() == April ||
ymd.month() == July || ymd.month() == October) &&
ymd.day() == day{1};
判断日期是否为年初第一天:只看 month() 和 day()
年初第一天固定是 1 月 1 日,不依赖年份值,也不涉及闰年逻辑。只需确认 month() 是 January 且 day() 是 1。
- 用
std::chrono::months{0}或January字面量都行,但别用整数1直接比较month()返回类型(它是std::chrono::month,非 int) - 如果输入是
time_t或system_clock::time_point,先转成sys_days再构造year_month_day,跳过时区影响 - 错误写法:
tm.tm_mon == 1 && tm.tm_mday == 1—— 这实际检查的是 2 月 1 日,因为tm_mon的 0 基索引常被忽略
auto ymd = std::chrono::year_month_day{sys_days{tp}};
bool is_year_first = ymd.month() == January && ymd.day() == day{1};
处理不同输入类型时的转换陷阱
C++20 的日历类型对输入格式很敏感,year_month_day 构造失败会返回无效值(ok() == false),不抛异常,容易静默出错。
- 输入是字符串(如
"2023-04-01")?必须先用std::chrono::parse解析,不能手动拆分再构造 - 输入是
time_t?用std::chrono::system_clock::from_time_t(t)转,再通过floor<days></days>对齐到日精度 - 输入是本地时间?
local_days会受时区偏移影响,若需统一按 UTC 判断,务必先转sys_days - 忘记检查
ymd.ok()就直接访问month(),可能得到month{0}这种未定义行为值
性能与可移植性提醒
std::chrono::year_month_day 构造本身开销极小,但 parse 或多次 floor<days></days> 调用会有微小成本。如果只是高频判断(如日志过滤),建议把日期预解析成 year_month_day 缓存,而不是每次从 time_point 重建。
- C++20 是硬性要求,C++17 及以前没有原生支持,得靠 Boost.Date_Time 或手写逻辑(比如
(m % 3 == 1) && d == 1配合m = tm_mon + 1) - MSVC 19.3x 对
parse的格式支持有 bug,比如不识别%Y-%m-%d中的%Y大写,建议降级用%y加逻辑补全世纪位 -
January、April是std::chrono::month类型字面量,头文件是<chrono></chrono>,不是<date></date>(后者是 Howard Hinnant 的第三方库)
季度和年初的判断本身很简单,真正容易卡住的是输入来源的标准化和类型安全转换——尤其是跨平台解析字符串或对接旧 C API 时,tm 结构体的字段偏移和范围陷阱比逻辑本身更值得花时间验证。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











