如何在 Windows 上获取精确的本地时区时间戳并提取 microseconds/nanoseconds

How to get a precise local timezone timestamp on Windows and extract microseconds/nanoseconds

问题描述

我想在 Windows 上获取精确的本地时区时间戳并将以下内容存储在结构中:

我正在寻找这个问题的 C 解决方案。

我的理解是 Windows 只能提供微秒级的粒度,但无论如何我都想将该信息存储为纳秒级。

我的用例

以下是我的用例的一些详细信息,以防它们相关。如果您不关心我的用例,可以跳过此部分。

我正在编写一个处理事件的程序。我无法在事件发生时订阅它们,而是需要定期轮询事件源。事件源不仅包含新事件,还包含事件的完整历史记录。

我需要创建一个时间戳,以便我只能从源处理比该时间戳更新的事件。

同一毫秒内可能发生多个事件,因此毫秒粒度对于我的用例来说太粗略了。

我还将我的时间戳保存到持久性存储中,这样程序停止或程序崩溃时上次处理事件的时间不会丢失。

我试过的

下面是我第一次尝试这样做。这可能是完全错误的,在这种情况下请跳转到我正在寻求帮助

void get_timestamp_now_local_timezone(timestamp *tstamp) {
    SYSTEMTIME st;
    SYSTEMTIME stLocal;
    FILETIME ft;

    GetSystemTimePreciseAsFileTime(&ft);
    FileTimeToSystemTime(&ft, &st);
    SystemTimeToTzSpecificLocalTime(NULL, &st, &stLocal);

    ULARGE_INTEGER large_int;
    large_int.LowPart = ft.dwLowDateTime;
    large_int.HighPart = ft.dwHighDateTime;
    ULONGLONG timeStamp = large_int.QuadPart;
    /* FILETIME has 100-nanosecond interval granularity */
    ULONGLONG nanoseconds = (timeStamp % 10000000) * 100;

    tstamp->year = stLocal.wYear;
    tstamp->month = stLocal.wMonth;
    tstamp->day = stLocal.wDay;
    tstamp->hour = stLocal.wHour;
    tstamp->minute = stLocal.wMinute;
    tstamp->second = stLocal.wSecond;
    tstamp->nanoseconds = nanoseconds;
}

我担心此代码可能存在一些错误:

可能的错误1

GetSystemTimePreciseAsFileTime() returns UTC 格式的时间。我担心由于跳跃 毫秒1,使用 UTC 格式 FILETIME 获取本地时区的纳秒可能不正确秒等可能因时区而异。

可能的错误2

我不确定我是否正确地复制到 ULARGE_INTEGER。我试图按照 FILETIME docs page:

上所说的进行操作

You should copy the low- and high-order parts of the file time to a ULARGE_INTEGER structure, perform 64-bit arithmetic on the QuadPart member, and copy the LowPart and HighPart members into the FILETIME structure

没有对应的例子,所以我可能做错了。

我正在寻求帮助

我上面的尝试可能是完全错误的,我可能找错了树。我将其包括在内更多是为了表明我在来到 Stack Overflow 之前尝试自己解决这个问题。

我想帮助解决我在上面 问题描述 中描述的问题,或者通过 A) 解释如何解决问题;或 B) 如果我对解决方案的尝试很接近(对此我表示怀疑),请指出我应该如何解决我对解决方案的尝试。


1 我被告知闰毫秒不存在(我不确定为什么我认为它们存在)

看来我的问题的答案是使用当地时间是错误的方法,正如 @chux - Reinstate Monica and @RbMm 在评论中指出的那样。

起初我认为我需要我的时间戳是本地时间,因为我的事件有本地时间时间戳,但在进一步阅读 Microsoft 文档后,我发现我的事件有 UTC 时间戳。 (如果有人感兴趣,可以在 this question 中找到有关我尝试处理的事件的更多详细信息。)

GetSystemTimePreciseAsFileTime() returns UTC 时间戳,所以我不需要执行任何转换。