【发布时间】:2018-03-05 20:49:09
【问题描述】:
我有一个 Windows C 程序,它从 unix 服务器下载文件及其修改时间。然后它将本地副本保存在缓存中,并将其时间戳设置为与服务器上的时间戳匹配 - 因此,如果本地副本是最新的,它就不需要提取新副本。
无论如何,它使用 utime() 将时间戳设置为 unix 主机报告的二进制值,然后使用 stat() 读取时间戳以检查文件是否过期。这曾经有效,但我只是注意到它不再有效了。
对于它的价值,时间差异是 3600 秒(1 小时),所以我猜这与 utime 和/或 stat 如何处理时区有关。我只是认为 stat 会向我报告我在 utime 中设置的相同修改时间值,但显然这是(不再是?)真的。我在这里看到了另一篇文章,其中提到了 Windows 的 stat 实现会扰乱夏令时 - 可能就是这样。
在 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
【问题讨论】:
-
好的。我发现另一篇文章解释了(以我不太明白的方式)在 NTFS 文件系统上,当夏令时无效时,stat() 返回错误的时间。正如我上面提到的那样,关闭一个小时。如果我关闭“自动调整夏令时时钟”复选框,问题就会消失。但我的问题仍然存在。有没有一种安全的方法来获取本地 Windows 文件的时间戳以匹配 unix 主机的时间戳?主机没有使用 64 位 UTC 并且具有 1970 年基准年,因此在 Windows 端切换到这些功能将不起作用 - 会吗?
-
这些 POSIX 函数通常不是“Windows”。它们由您使用的任何 C 运行时库提供。我无法使用第一个作为公共 Windows 组件(即通用 CRT)正式分发的 C 运行时来重现这一点。我建议您检查
_utime实际设置的内容。致电GetFileTime以检查lpLastWriteTime(自 1601-01-01,UTC 起为 100 ns 单位)。除以 10,000,000 并减去 11,644,473,600 以将其转换为 Unix 时间戳。 -
我尝试了您的 GetFileTime 方法,在将 lpLastWriteTime 转换为 unix 时间戳后,它与 statbuf.st_mtime 产生的“关闭 1 小时”值匹配。所以,我想这意味着我真正需要使用的是 SetFileTime 而不是 utime() - 然后 stat 就可以工作了。
-
是的。我刚试过。如果我反转您的时间计算(将 unix 时间戳转换为 Windows UTC)并使用 SetFileTime 设置 lpLastWriteTime,随后对 stat 的调用将返回原始 unix 文件时间,并且我的缓存时间戳检查成功。非常感谢。