5

我再次从 Windows 转到 Linux,我必须将计算 NTP 时间的函数从 Windows 移植到 Linux。看起来很简单,但格式是 WindowsFILETIME格式。我有点知道有什么区别,但到目前为止,我无法正确地将我的 Linux 时间转换为 WindowsFILETIME格式。有人对如何做到这一点有任何想法吗?

我看过一些关于如何做到这一点的文章,但它们都使用 Win32 函数,我不能使用它们!如果这没有意义,我可以发布 Windows 代码。

他们还采用当前时间并从 1900 年 1 月 1 日减去它以获得增量以找到 NTP,我假设在 Linux 中我只是添加

const unsigned long EPOCH   = 2208988800UL

到我得到这个结果的时间?

4

3 回答 3

10

FILETIME结构的 Microsoft 文档解释了它是什么。基本思想是,Windows从 1601 年 1 月 1 日FILETIME起按 10 -7秒(100 纳秒间隔)的步长计数(为什么是 1601?不知道......)。在 Linux 中,您可以使用gettimeofday(). 因此,以下 C 函数可以完成这项工作:

#include <sys/time.h>
/**
 * number of seconds from 1 Jan. 1601 00:00 to 1 Jan 1970 00:00 UTC
 */
#define EPOCH_DIFF 11644473600LL

unsigned long long
getfiletime() {
    struct timeval tv;
    unsigned long long result = EPOCH_DIFF;
    gettimeofday(&tv, NULL);
    result += tv.tv_sec;
    result *= 10000000LL;
    result += tv.tv_usec * 10;
    return result;
}
于 2010-11-09T14:50:46.833 回答
5

首先,为什么是1601?因为公历每 400 年重复一次,而预测的公历从 0001-01-01 开始。所以 1601 是 1980(1970,...)之前的最后一个周期开始,这简化了计算。(哦,这就是为什么第三个千年始于 2001 年 1 月 1 日,而不是2000 年 1 月 1 日……)

要使用 FILETIME 的二进制分数创建类似 NTP 时间戳的东西,

  1. 移动纪元的原点,使用 LONGLONG 或 ULONGLONG 来表示 FILETIME 的刻度。
  2. 将刻度除以 10^7 以得到秒(作为商)和分数(作为余数)。如果您纯粹以无符号计算,只需除以即可。但在这种情况下,您不能表示负值。
  3. 无符号将 64 位中的分数(必须 >= 0)乘以 1844674407371ull,即 2^64 / 10^7(四舍五入)
  4. 取乘积的高 32 位作为 NTP 时间戳的二进制小数。(您可能希望从产品的低 32 位进行舍入。请注意,只要小数刻度严格低于 10^7,就不会发生舍入到整秒的情况。)
于 2013-09-18T10:50:14.287 回答
2

假设您从废弃某个网站中获取时间戳值。你定义

unsigned __int64 timestamp = 0;

您获取的值可能需要除以 1000。

if (element.HasMember(L"timestamp"))
{
    timestamp = element[L"timestamp"].GetUint64() / 1000;
}                                       }

然后你做如下:

LONGLONG ll;
ll = Int32x32To64(timestamp, 10000000) + 116444736000000000;
FILETIME ft;
ft.dwLowDateTime = (DWORD)ll;
ft.dwHighDateTime = ll >> 32;
SYSTEMTIME stTime;
FileTimeToSystemTime(&ft, &stTime);
于 2017-01-03T12:13:57.177 回答