C++与JavaScript间纪元时间的正确转换与交互问题
C++ std::chrono与JSON时间互转及相关问题解答
问题代码及现存问题
struct MyChronoObject { std::string name; std::chrono::system_clock::time_point birthday; MyChronoObject(const std::string name_) : name(name_) { birthday = std::chrono::system_clock::now(); } std::string toJSON1() { std::string s = "{ \"name\": \"" + name + "\", \"birthday\": "; s += std::to_string((birthday.time_since_epoch().count() / 1000000)); s += " }"; return s; } std::string toJSON2() { std::string s = "{ \"name\": \"" + name + "\", \"birthday\": "; s += std::to_string((birthday.time_since_epoch().count())); s += " }"; return s; } void setBirthday(int birthday_in_seconds) { // how do I properly cast this? } };
代码存在的精度匹配问题:
toJSON1()输出的16687719115既不符合秒级(少一位)也不符合毫秒级(多两位)的Epoch时间格式toJSON2()输出的16687747280849928既不是正确的微秒(多一位)也不是纳秒(少两位)格式
核心问题:正确高效存储/转换Epoch时间以适配JavaScript
JavaScript的Date对象默认接受毫秒级Epoch时间戳,C++侧需通过类型安全的chrono转换实现精准输出,避免手动计算出错:
修改后的标准JSON转换方法:
std::string toJSON() { // 将时间点转换为毫秒级时长 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(birthday.time_since_epoch()); std::string s = "{ \"name\": \"" + name + "\", \"birthday\": " + std::to_string(ms.count()) + " }"; return s; }
输出的毫秒级时间戳可直接被new Date(timestamp)在JS中正确解析。
相关技术疑问解答
1. 前端数值转C++ chrono时间点
根据前端传入的时间戳精度选择对应chrono时长类型转换:
- 若传入秒级时间戳:
void setBirthday(long long birthday_in_seconds) { auto secs = std::chrono::seconds(birthday_in_seconds); birthday = std::chrono::system_clock::time_point(secs); }
- 若传入毫秒级时间戳:
void setBirthday(long long birthday_in_ms) { auto ms = std::chrono::milliseconds(birthday_in_ms); birthday = std::chrono::system_clock::time_point(std::chrono::duration_cast<std::chrono::system_clock::duration>(ms)); }
注意:推荐用long long存储时间戳,避免2038年及更早日期的溢出问题。
2. 仅需秒级精度,是否仍用chrono对象存储?
建议继续使用std::chrono::system_clock::time_point存储,原因:
- 类型安全,避免手动管理单位时出错
- 扩展性强,后续如需更高精度无需修改存储结构
- 支持直接进行时间运算,比手动计算数值更可靠
若追求极致简化,也可改用std::chrono::seconds存储,但会损失时间点的语义表达。
3. 精确增加一年并保持日期一致(考虑闰年)
std::chrono本身无直接的"加一年"接口,需借助日期类型处理:
- C++20及以上:使用标准库
<chrono>中的日历类型 - 旧版本:依赖第三方库如date.h
C++20实现示例:
#include <chrono> void addOneYear() { // 将时间点转换为日历日期 auto ymd = std::chrono::year_month_day(std::chrono::floor<std::chrono::days>(birthday)); // 年份加1,自动处理闰年逻辑 auto new_ymd = ymd.year() + std::chrono::years(1) / ymd.month() / ymd.day(); // 转换回时间点 birthday = std::chrono::system_clock::from_sys(std::chrono::sys_days(new_ymd)); }
该实现会自动适配闰年:例如2020年2月29日加一年会转为2021年2月28日。
4. 处理1970年之前的日期
std::chrono::system_clock::time_point支持表示1970年1月1日之前的时间(对应负的时长数值):
- 转换为Epoch时间戳时会输出负数,JavaScript的
Date对象可正确解析 - 如需转换为日历日期,C++20标准库的日历类型支持公元前日期,旧版本需借助第三方日期库处理
注意:存储时间戳时需用有符号整数类型(如long long),避免溢出。
内容的提问来源于stack exchange,提问作者Markstar
相关产品推荐
相关产品推荐

