如何用C++转换1899/12/30起的十进制日期为可读时间并计算秒差
在C++中转换Excel风格日期为可读格式并计算秒差
我来帮你搞定这个问题!你提到的这种日期格式是Excel和Access常用的序列化方式——整数部分代表从1899年12月30日开始经过的完整天数,小数部分则是当天时间占一整天的比例(比如0.5就是中午12点)。下面分两部分给出解决方案:
一、转换为人类可读的日期时间
我们可以利用C++11及以后的<chrono>标准库来处理日期计算,再结合<iomanip>和<ctime>来格式化输出。核心思路是:
- 把输入的天数数值转换为总秒数(1天=86400秒)
- 计算从1899-12-30 00:00:00到目标时间的时间间隔
- 将这个时间间隔转换为系统时钟的时间点,最后格式化输出
代码示例:
#include <iostream> #include <chrono> #include <iomanip> #include <ctime> #include <sstream> // 定义Excel日期的起始点:1899年12月30日 00:00:00 const auto excel_epoch = []() { std::tm tm{}; tm.tm_year = 1899 - 1900; // tm_year是从1900年开始的差值 tm.tm_mon = 12 - 1; // tm_mon从0开始(1月=0) tm.tm_mday = 30; tm.tm_hour = 0; tm.tm_min = 0; tm.tm_sec = 0; // 转换为system_clock的时间点 return std::chrono::system_clock::from_time_t(std::mktime(&tm)); }(); // 将Excel日期转换为可读字符串(格式:YYYY-MM-DD HH:MM:SS) std::string excel_date_to_string(double excel_date) { // 计算总秒数:天数 * 86400秒/天 const auto total_seconds = std::chrono::duration_cast<std::chrono::seconds>( std::chrono::duration<double, std::ratio<86400>>(excel_date) ); // 计算目标时间点 const auto target_time = excel_epoch + total_seconds; // 转换为本地时间的tm结构 std::time_t target_time_t = std::chrono::system_clock::to_time_t(target_time); std::tm local_tm = *std::localtime(&target_time_t); // 格式化输出 std::ostringstream oss; oss << std::put_time(&local_tm, "%Y-%m-%d %H:%M:%S"); return oss.str(); } int main() { double test_date = 40097.586458333; std::cout << "可读日期时间:" << excel_date_to_string(test_date) << std::endl; return 0; }
这段代码的关键点:
- 用lambda表达式一次性构造了Excel的起始时间点,避免重复计算
- 用
std::chrono::duration处理带小数的天数,转换为秒数时自动处理浮点精度问题 - 最后用
std::put_time生成符合日常阅读习惯的日期字符串
二、计算两个日期的秒差
这个逻辑非常直接:因为每个Excel日期的单位是1天,所以两个日期的差值乘以86400(一天的总秒数)就能得到秒级差值。如果需要更精确的结果,可以保留浮点计算的精度。
代码示例:
#include <iostream> #include <cmath> constexpr double SECONDS_PER_DAY = 86400.0; // 计算两个Excel日期的秒级差值(返回绝对值) double calculate_second_diff(double date1, double date2) { return std::abs(date1 - date2) * SECONDS_PER_DAY; } int main() { double date_a = 40097.5865162037; double date_b = 40097.586458333; double diff = calculate_second_diff(date_a, date_b); std::cout << "两个日期的秒差:" << diff << " 秒" << std::endl; // 计算结果约为5.0秒(0.0000578707 * 86400 ≈ 5) return 0; }
如果需要更高精度的时间差,可以改用long double类型进行计算,避免浮点截断误差。
内容的提问来源于stack exchange,提问作者shaikh
相关产品推荐
相关产品推荐

