You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Clang编译器实现常规时间与Epoch时间互转的问题排查

Clang下日期时间与Epoch时间双向转换异常问题解决

我需要用Clang编译器实现常规日期时间和Epoch时间的双向转换,现有C代码在g下运行正常,但在本地Clang 14.0.0下运行异常,推测是strptime和strftime函数失效。以下是代码及两种编译器的输出:

// #include <chrono>
#include <iostream>
#include <cstring>

uint64_t timeToEpoch(uint64_t day, uint64_t month, uint64_t year, uint64_t hour, uint64_t min, uint64_t second, uint64_t microsecond){
    // std::cout << day << "-" << month << "-" << year << " " << hour << ":" << min << ":" << second << ":" << microsecond << std::endl;
    std::string timeT = std::to_string(day) + "-" + std::to_string(month) + "-" + std::to_string(year) + " " + std::to_string(hour) + ":" + std::to_string(min) + ":" + std::to_string(second);
    // std::cout << timeT << std::endl;
    char *time_T = new char[(timeT.length() + 1)];
    strcpy(time_T, timeT.c_str());
    // std::cout << time_T << std::endl;
    struct tm tm;
    strptime(time_T, "%d-%m-%Y %H:%M:%S", &tm);
    // std::cout << mktime(&tm) << std::endl;
    uint64_t t = mktime(&tm);
    t = (t * 1000000) + microsecond;
    return t;
}

std::string epochToTime(uint64_t epochTime){
    std::string timeT;
    uint64_t microsecond = epochTime % 1000000;
    time_t epochTimeInSec = (epochTime - microsecond) / 1000000;
    char time_T[21];
    strftime(time_T, 20, "%d-%m-%Y %H:%M:%S", localtime(&epochTimeInSec));
    timeT = time_T;
    timeT = timeT + ":" + std::to_string(microsecond);
    return timeT; 
}

int main()
{
    std::cout << "Year changed 2004 to 2005\n";
    uint64_t time_info_1 = timeToEpoch(31, 12, 2004, 23, 59, 59, 999999);
    uint64_t time_info_2 = timeToEpoch(1, 1, 2005, 0, 0, 0, 9);
    std::cout << "First timestamp in epoch :" << time_info_1 << "\n";
    std::cout << "Second timestamp in epoch: " << time_info_2 << "\n\n";
    std::cout << "Difference between both timestamp in microsecond: " << (time_info_2 - time_info_1) << "\n\n";
    std::cout << "First timestamp converted from epoch: " << epochToTime(time_info_1) << "\n";
    std::cout << "Second timestamp converted from epoch: " << epochToTime(time_info_2) << "\n";
    return 0;
}

g++输出:

Year changed 2004 to 2005
First timestamp in epoch :1104517799999999
Second timestamp in epoch: 1104517800000009

Difference between both timestamp in microsecond: 10

First timestamp converted from epoch: 31-12-2004 23:59:59:999999
Second timestamp converted from epoch: 01-01-2005 00:00:00:9

clang++输出:

Year changed 2004 to 2005
First timestamp in epoch :18446744073709551615
Second timestamp in epoch: 18446744073708551625

Difference between both timestamp in microsecond: 18446744073708551626

First timestamp converted from epoch: 19-01-586524 13:31::551615
Second timestamp converted from epoch: 19-01-586524 13:31::551625

问题原因

  1. 未初始化struct tm变量:strptime只会填充匹配到的字段,未匹配的字段保留垃圾值,导致mktime返回-1(转换失败),强制转为uint64_t后溢出成最大值。
  2. strptime是POSIX标准函数:Clang默认可能未启用POSIX扩展,导致函数无法正常工作。
  3. 类型转换无安全检查:time_t是有符号类型,直接转为无符号uint64_t会掩盖错误。

修复后的代码

#include <iostream>
#include <cstring>
#include <ctime>
#include <stdexcept>

// 定义POSIX宏,确保Clang识别strptime
#define _POSIX_C_SOURCE 200809L

uint64_t timeToEpoch(uint64_t day, uint64_t month, uint64_t year, uint64_t hour, uint64_t min, uint64_t second, uint64_t microsecond){
    std::string timeT = std::to_string(day) + "-" + std::to_string(month) + "-" + std::to_string(year) + " " + 
                        std::to_string(hour) + ":" + std::to_string(min) + ":" + std::to_string(second);
    
    struct tm tm{}; // 初始化结构体为0,避免垃圾值
    if (!strptime(timeT.c_str(), "%d-%m-%Y %H:%M:%S", &tm)) {
        throw std::invalid_argument("日期格式无效");
    }

    tm.tm_isdst = -1; // 让mktime自动判断夏令时
    time_t t = mktime(&tm);
    if (t == -1) {
        throw std::runtime_error("无法将tm转换为time_t");
    }

    return static_cast<uint64_t>(t) * 1000000 + microsecond;
}

std::string epochToTime(uint64_t epochTime){
    uint64_t microsecond = epochTime % 1000000;
    time_t epochTimeInSec = static_cast<time_t>((epochTime - microsecond) / 1000000);
    
    struct tm* local_tm = localtime(&epochTimeInSec);
    if (!local_tm) {
        throw std::runtime_error("无法将time_t转换为本地时间");
    }

    char time_T[21];
    if (strftime(time_T, sizeof(time_T), "%d-%m-%Y %H:%M:%S", local_tm) == 0) {
        throw std::runtime_error("格式化时间字符串失败");
    }

    std::string timeT = time_T;
    timeT += ":" + std::to_string(microsecond);
    return timeT; 
}

int main()
{
    try {
        std::cout << "Year changed 2004 to 2005\n";
        uint64_t time_info_1 = timeToEpoch(31, 12, 2004, 23, 59, 59, 999999);
        uint64_t time_info_2 = timeToEpoch(1, 1, 2005, 0, 0, 0, 9);
        std::cout << "First timestamp in epoch :" << time_info_1 << "\n";
        std::cout << "Second timestamp in epoch: " << time_info_2 << "\n\n";
        std::cout << "Difference between both timestamp in microsecond: " << (time_info_2 - time_info_1) << "\n\n";
        std::cout << "First timestamp converted from epoch: " << epochToTime(time_info_1) << "\n";
        std::cout << "Second timestamp converted from epoch: " << epochToTime(time_info_2) << "\n";
    } catch (const std::exception& e) {
        std::cerr << "错误: " << e.what() << std::endl;
        return 1;
    }
    return 0;
}

关键修复点

  • 定义_POSIX_C_SOURCE宏,启用POSIX扩展,确保Clang支持strptime。
  • 初始化struct tm为零值,清除垃圾值干扰。
  • 设置tm_isdst = -1,让mktime自动处理夏令时,避免转换错误。
  • 添加函数调用的错误检查,抛出异常提示错误原因,避免无意义的溢出值。
  • 安全处理类型转换,明确使用static_cast,避免隐式转换导致的问题。

内容的提问来源于stack exchange,提问作者Akash Sagar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 12:15:11