如何用std::chrono从毫秒级Epoch时间提取时间单位并操作日期?
解决C++中Epoch毫秒时间的日期提取与操作问题
需要注意:以下方案基于C++20及以上版本实现,标准库从C20开始正式引入chrono日历与时区组件。若使用旧版本C,需依赖Howard Hinnant的date第三方库(此处仅讲解标准库原生方案)。
1. 提取年、月、日、时、分、秒、毫秒
要从system_clock::time_point中提取时间单位,需先将其转换为结构化的日历类型(如year_month_day)和时分秒毫秒类型(如hh_mm_ss<milliseconds>)。以下是完整的getTimeUnit函数实现:
#include <chrono> #include <iostream> enum class DatePrecision { YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, MILLI }; using namespace std::chrono; int getTimeUnit(const system_clock::time_point& tp, const DatePrecision dp) { // 将时间点向下取整到UTC当天起始时刻,得到天数级的时间戳 const auto utc_days = floor<days>(tp); // 转换为年-月-日结构化类型 const year_month_day ymd{utc_days}; // 计算当天已流逝的毫秒数,并解析为时-分-秒-毫秒 const auto ms_since_midnight = floor<milliseconds>(tp - utc_days); const hh_mm_ss hms{ms_since_midnight}; switch (dp) { case DatePrecision::YEAR: return static_cast<int>(ymd.year()); case DatePrecision::MONTH: return static_cast<unsigned>(ymd.month()); case DatePrecision::DAY: return static_cast<unsigned>(ymd.day()); case DatePrecision::HOUR: return hms.hours().count(); case DatePrecision::MINUTE: return hms.minutes().count(); case DatePrecision::SECOND: return hms.seconds().count(); case DatePrecision::MILLI: return hms.subseconds().count(); default: return -1; } } int main() { long long et = 1693322440062; milliseconds ms{et}; system_clock::time_point tp(ms); std::cout << "Year: " << getTimeUnit(tp, DatePrecision::YEAR) << "\n"; std::cout << "Month: " << getTimeUnit(tp, DatePrecision::MONTH) << "\n"; std::cout << "Day: " << getTimeUnit(tp, DatePrecision::DAY) << "\n"; std::cout << "Hour: " << getTimeUnit(tp, DatePrecision::HOUR) << "\n"; std::cout << "Minute: " << getTimeUnit(tp, DatePrecision::MINUTE) << "\n"; std::cout << "Second: " << getTimeUnit(tp, DatePrecision::SECOND) << "\n"; std::cout << "Milli: " << getTimeUnit(tp, DatePrecision::MILLI) << "\n"; return 0; }
代码说明
floor<days>(tp):将时间点向下取整到UTC当天的午夜时刻,得到代表Epoch以来天数的sys_days类型。year_month_day{utc_days}:将天数转换为可读的年、月、日结构化数据。tp - utc_days:计算当天已流逝的时长,转换为毫秒后用hh_mm_ss解析为时、分、秒、毫秒。- 上述代码默认处理UTC时间,若需要本地时间,需结合时区转换(见下文)。
2. 日期比较
chrono库已为time_point重载了所有比较运算符,直接使用即可:
system_clock::time_point tp1 = milliseconds{1693322440062}; system_clock::time_point tp2 = milliseconds{1693408840000}; if (tp1 < tp2) { std::cout << "tp1 早于 tp2\n"; }
若需比较年、月、日等日历单元,可先转换为year_month_day再比较:
year_month_day ymd1 = floor<days>(tp1); year_month_day ymd2 = floor<days>(tp2); if (ymd1 == ymd2) { std::cout << "两个时间点属于同一天\n"; }
3. 添加/减去小时、天数、月份
加减固定时长(小时、天数)
直接对time_point加减chrono::duration类型即可:
// 添加2小时 auto tp_plus_2h = tp + hours{2}; // 减去3天 auto tp_minus_3d = tp - days{3};
加减月份(日历级操作)
由于不同月份天数不同,需先转换为year_month_day,结合months类型操作后再转回time_point:
year_month_day ymd = floor<days>(tp); // 添加1个月 auto ymd_plus_1m = ymd + months{1}; // 转换回system_clock的时间点 auto tp_plus_1m = system_clock::from_sys(sys_days{ymd_plus_1m});
4. 处理本地时间(替代UTC)
若需要将UTC时间转换为系统本地时间,需使用时区组件:
#include <chrono> #include <iostream> int main() { long long et = 1693322440062; milliseconds ms{et}; system_clock::time_point tp_utc(ms); // 获取当前系统的本地时区 const auto& local_tz = std::chrono::current_zone(); // 将UTC时间转换为本地时间 auto tp_local = local_tz->to_local(tp_utc); // 提取本地日期和时间 auto local_days = floor<days>(tp_local); year_month_day ymd_local{local_days}; auto ms_local = floor<milliseconds>(tp_local - local_days); hh_mm_ss hms_local{ms_local}; std::cout << "本地年份: " << static_cast<int>(ymd_local.year()) << "\n"; std::cout << "本地小时: " << hms_local.hours().count() << "\n"; return 0; }
常见问题解决
- 无法运行cppreference示例:确保编译器启用C++20标准(GCC:
-std=c++20,MSVC:/std:c++20,Clang:-std=c++20)。 utc_time与system_time的区别:system_clock::time_point本质就是UTC时间(sys_time),utc_time是更明确的UTC时间类型,两者可互相转换:utc_time<milliseconds> utc_tp{tp.time_since_epoch()};
内容的提问来源于stack exchange,提问作者Markstar
相关产品推荐
相关产品推荐

