将 Unix/Linux 时间转换为 Windows FILETIME

发布于 2024-09-15 23:43:19 字数 434 浏览 9 评论 0 原文

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

我看过一些关于如何执行此操作的文章,但它们都使用 Win32 函数,而我无法使用它们!如果这没有意义,我可以发布 Windows 代码。

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

const unsigned long EPOCH   = 2208988800UL

与我的时间相加即可得到这个结果?

I am once again going from Windows to Linux, I have to port a function from Windows to Linux that calculates NTP time. Seems simple but the format is in Windows FILETIME format. I sort of have an idea what the differences are but so far I can not correctly convert my Linux time to the Windows FILETIME format. Does anyone have any ideas on how to do this?

I have seen some articles on how to do this but they all use Win32 functions and I can't use them! I can post the Windows code if this makes no sense.

They also take the current time and subtract it from January 1st 1900 to get the delta to find NTP, I would assume in Linux I just add the

const unsigned long EPOCH   = 2208988800UL

to my time to get this result?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

独自唱情﹋歌 2024-09-22 23:43:19

FILETIME 结构解释了它是什么。基本思想是 Windows FILETIME 从 1601 年 1 月 1 日开始以 10-7 秒(100 纳秒间隔)为单位进行计数(为什么是 1601 年?不知道... )。在 Linux 中,您可以使用 -6)。 2.html" rel="noreferrer">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;
}

The Microsoft documentation for the FILETIME structure explains what it is. The basic idea is that a Windows FILETIME counts by steps of 10-7 seconds (100-nanosecond intervals) from 1 Jan 1601 (why 1601? no idea...). In Linux you can obtain time in microseconds (10-6) from 1 Jan 1970 using gettimeofday(). Thus the following C function does the job:

#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;
}
心凉怎暖 2024-09-22 23:43:19

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

(哦,这 FILETIME,

  1. 使用 LONGLONG 或 ULONGLONG 移动纪元的原点
    代表 FILETIME 的刻度。
  2. 将刻度除以 10^7 即可得到秒数(如
    商)和分数(作为余数)。如果你计算
    纯粹是无符号的,简单除法。但你不能代表消极
    在这种情况下的值。
  3. 无符号将 64 位中的分数(必须 >= 0)乘以
    1844674407371ull,即2^64 / 10^7(四舍五入)
  4. 取乘积的高32位作为二进制小数
    NTP 时间戳。 (您可能想要从低 32 位开始舍入
    产品。请注意,四舍五入进位到整秒不能
    只要小数刻度严格低于 10^7,就会发生。)

First, why 1601? Because the Gregorian Calendar repeats itself every 400 years, and the proleptic Gregorian Calendar starts with 0001-01-01. So 1601 was the last cycle start before 1980(1970,...) and that simplifies the calculations. (Oh, and that's why the 3rd millenium started on 2001-01-01, and not on 2000-01-01...)

To create something like a NTP time stamp with a binary fraction from a FILETIME,

  1. Shift the origin of the epoch, using a LONGLONG or ULONGLONG to
    represent the FILETIME's ticks.
  2. Do a floor division of the ticks by 10^7 to get the seconds (as
    quotient) and the fraction (as the remainder). If you calculate
    purely in unsigned, simply divide. But you cannot represent negative
    values in that case.
  3. Unsigned multiply the fraction (which must be >= 0) in 64 bits by
    1844674407371ull, which is 2^64 / 10^7 (rounded)
  4. Take the upper 32 bits of the product as the binary fraction of the
    NTP time stamp. (You might want to round from the lower 32 bits of
    the product. Note that a rounding carry into the full seconds cannot
    occur as long as the fractional ticks are strict below 10^7.)
孤蝉 2024-09-22 23:43:19

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

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);

Assuming you fetch the timestamp value from scrapping some website. You define

unsigned __int64 timestamp = 0;

The value you fetch might need to be divided by 1000.

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

then you do as follow:

LONGLONG ll;
ll = Int32x32To64(timestamp, 10000000) + 116444736000000000;
FILETIME ft;
ft.dwLowDateTime = (DWORD)ll;
ft.dwHighDateTime = ll >> 32;
SYSTEMTIME stTime;
FileTimeToSystemTime(&ft, &stTime);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文