utime()和stat()之间的时区差异

时间:2018-03-05 20:49:09

标签: winapi timezone stat

我有一个Windows C程序,可以从unix服务器下载文件及其修改时间。然后,它将本地副本保存在缓存中,并将其时间戳设置为与服务器上的时间戳匹配 - 因此,如果本地副本是最新的,则无需提取新副本。

无论如何,它使用utime()将时间戳设置为unix主机报告的二进制值,然后使用stat()读回时间戳以检查文件是否过期。这曾经有用,但我注意到它不再起作用了。

对于它的价值,时间的差异是3600秒(1小时),所以我猜这与utime和/或stat如何处理时区有关。我只是认为stat会向我报告我在utime中设置的相同修改时间值,但显然是(不再是?)true。我在这里看过另一篇帖子,提到Windows实施统计数据会让人节省夏令时 - 所以可能就是这样。

是否有更正确的方法在Windows中执行此操作 - 同时仍使用POSIX时间函数。请记住,我正在尝试获取本地文件的二进制mod时间(由Windows报告)以匹配主机文件的mod时间(由unix上的stat报告)。

以下是一些显示问题的示例代码。 fc-> timestamp是从服务器发送的值。我将它复制到utimes,调用utime()和stat(),并且statbuf.st_mtime与其他人不同3600秒:

// Set the local file's timestamp to the host's value
utimes.actime = utimes.modtime = fc->timestamp;
utime(szTempPath2, &utimes);
// Now call stat to see what time registers there.
if (stat(szTempPath2, &statbuf) == 0) {
if (fc->timestamp != statbuf.st_mtime)
        fc->timestamp = statbuf.st_mtime;
}

When I'm done the values are:
fc->timestamp = 1359772839
utimes.modtime = 1359772839
statbuf.st_mtime = 1359776439 <<== this is 3600 more than the others

1 个答案:

答案 0 :(得分:0)

原来,utime()是罪魁祸首。

如果你使用utime来设置mod时间,如果NTFS夏令时问题生效,stat()和GetFileTime()都将返回你的时间+ 1小时。但是如果你使用SetFileTime,stat()和GetFileTime都将返回你设置的时间 - 无论NTFS如何处理夏令时。

所以,它就像上面评论中描述的erkysun一样,除了你需要反转windows-to-unix时间戳计算,而是将unix时间戳转换为自1/1/1601以来的windows UTC微秒(使用常数erkysun提供)。像这样:

ulong     unix_timestamp;
ULONGLONG win_timestamp;
ULARGE_INTEGER li;
HFILE     hFile;
FILETIME  filetime;

   if (hFile = CreateFile(szTempPath2, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 
                          FILE_ATTRIBUTE_NORMAL, NULL)) {
      // Convert the unix timestamp to Windows UTC time
      // 1/1/1970 unix base date (seconds) to 1/1/1601 windows base date
      win_timestamp = unix_timestamp + 11644473600;
      // seconds to 100's of nanoseconds
      win_timestamp *= 10000000;
      // Copy the long long int into filetime high/low and
      // use to set the access and mod times.
      li.QuadPart = win_timestamp;
      filetime.dwHighDateTime = li.HighPart;
      filetime.dwLowDateTime = li.LowPart;
      SetFileTime(hFile, NULL, &filetime, &filetime);
      CloseHandle(hFile);
  }