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

为何C++获取的Epoch秒数在C# DateTime中转换出现偏差?

问题:C++获取的文件修改时间Epoch秒数在C#转换后时区不符

我有一个C++方法用于获取文件最后修改时间,返回从Epoch(1970年1月1日)开始的秒数,代码如下:

const HANDLE handle = CreateFile(filePath.c_str(), // file to open
                                 GENERIC_READ,     // open for reading
                                 FILE_SHARE_READ,  // share for reading
                                 nullptr,          // default security
                                 OPEN_EXISTING,    // Open existing file only if it exists, and only intact.
                                 FILE_FLAG_BACKUP_SEMANTICS,
                                 nullptr); // no attr.
if (INVALID_HANDLE_VALUE == handle)
{
    ThrowWindowsErrorMessage(__CODE_LOCATION__);
}

if (BY_HANDLE_FILE_INFORMATION fileInformation; 0 == GetFileInformationByHandle(handle, &fileInformation))
{
    ThrowWindowsErrorMessage(__CODE_LOCATION__);
}
else
{
    SYSTEMTIME systemTime;
    if (0 == FileTimeToSystemTime(&fileInformation.ftLastWriteTime, &systemTime))
    {
        ThrowWindowsErrorMessage(__CODE_LOCATION__);
    }
    else
    {
        tm tim = {0};
        tim.tm_sec = systemTime.wSecond;
        tim.tm_min = systemTime.wMinute;
        tim.tm_hour = systemTime.wHour;
        tim.tm_mday = systemTime.wDay;
        tim.tm_mon = systemTime.wMonth - 1;
        tim.tm_year = systemTime.wYear - 1900;
 
        // daylight time applies or not.
        tim.tm_isdst = -1;

        const time_t t0 = mktime(&tim);
        if (static_cast<time_t>(-1) != t0)
        {
            tTime = t0;
        }
    }
}
CloseHandle(handle);
return tTime;

运行时,systemTime符合本地UTC+2时区(本地9:35对应UTC 7:35),返回的tTime值为1667453701。

但在C#中用以下代码构造DateTime对象时:

var lastModifiedFileTime = new DateTime(1970, 1,1).AddSeconds(1667453701);

得到的时间显示为5:35,比预期少2小时。期望两者归一化到UTC后数值一致,请问问题原因及修复方法?


问题原因

  1. C++端的时区转换逻辑:

    • fileInformation.ftLastWriteTime是Windows系统存储的UTC时间,通过FileTimeToSystemTime转换后得到的systemTime是**本地时区(UTC+2)**的时间。
    • mktime函数的作用是将本地时间转换为从1970-01-01 UTC开始的Epoch秒数,所以最终返回的1667453701对应的是UTC 7:35,这部分是正确的。
  2. C#端的基准时间时区错误:

    • new DateTime(1970, 1, 1)默认创建的是本地时区的1970年1月1日,调用AddSeconds(1667453701)后得到的仍然是本地时区的时间。
    • 由于你的本地时区是UTC+2,C#会把Epoch秒数对应的UTC时间再转换一次到本地时区,导致出现双重转换错误,最终显示的时间比预期少2小时。

修复方案

方案1:C#中直接构造UTC时间(推荐)

使用DateTime.UnixEpoch(.NET Core 2.1+/NET 5+)或显式指定DateTimeKind.Utc来创建基准时间,确保转换后的时间是UTC时区:

// 方法1:使用UnixEpoch(简洁高效)
var lastModifiedFileTime = DateTime.UnixEpoch.AddSeconds(1667453701);

// 方法2:显式指定UTC类型(兼容旧版.NET Framework)
var lastModifiedFileTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(1667453701);

此时得到的lastModifiedFileTime会显示为UTC 7:35,与C++端的预期一致。

方案2:C#中转换为本地时间

如果需要得到对应本地时区的时间(即C++中的9:35),可以将UTC时间转换为本地时区:

var utcTime = DateTime.UnixEpoch.AddSeconds(1667453701);
var localTime = utcTime.ToLocalTime();

优化C++代码(避免时区转换误差)

可以直接将FILETIME转换为Epoch秒数,跳过本地时间转换步骤,避免时区相关的潜在问题:

ULARGE_INTEGER ft;
ft.LowPart = fileInformation.ftLastWriteTime.dwLowDateTime;
ft.HighPart = fileInformation.ftLastWriteTime.dwHighDateTime;
// FILETIME是从1601-01-01 UTC开始的100纳秒单位,转换为1970-01-01 UTC的秒数
const time_t epochSeconds = (ft.QuadPart - 116444736000000000LL) / 10000000LL;
tTime = epochSeconds;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 09:55:20