Problem Description
I want to get a precise local timezone timestamp on Windows and store the following in a struct:
- Day
- Month
- Year
- Hour
- Minute
- Second
- Nanosecond
I am looking for a C solution to this problem.
My understanding is that Windows can only provide microsecond granularity, but I want to store that information as nanoseconds anyway.
My use case
Here are some details on my use case, in case they are relevant. This section can be skipped if you are not concerned with my use case.
I am writing a program that processes events. I am unable to subscribe to events as they occur, and instead I need to poll the event source periodically. The event source does not contain only new events, but it contains the full history of events.
I need to create a timestamp so I can only process events newer than this timestamp from the source.
More than one event can occur within the same millisecond, and therefore millisecond granularity is too coarse for my use case.
I also save my timestamp to persistent storage so that the time of the last event processed is not lost of the program is stopped or the program crashes.
What I tried
Below is my first stab at doing this. This could be totally wrong, in which case please jump to What I am seeking help with.
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;
}
I am concerned about a couple possible errors with this code:
Possible error 1
GetSystemTimePreciseAsFileTime()
returns time in UTC format. I am concerned that operating on the UTC format FILETIME
to get the nanoseconds in the local timezone might be incorrect due to leap milliseconds1 seconds and such that might differ between timezones.
Possible error 2
I'm not sure if I am copying into the ULARGE_INTEGER
correctly. I was trying to follow what was said on the 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
There was no corresponding example, so I could have done this wrong.
What I am seeking help with
My attempt above could be totally wrong and I could be barking up the wrong tree. I include it more to show that I attempted to solve this problem on my own before coming to Stack Overflow.
I would like help with how to solve the problem I described in Problem Description above, either by A) explaining how to solve the problem; or B) if my attempt at a solution is close (which I doubt), by pointing out what I should do to fix my attempt at a solution.
1 I've been informed that leap milliseconds don't exist (I'm not sure why I thought they did)
CodePudding user response:
It looks like the answer to my question is that using local time is the wrong way to go, as pointed out by @chux - Reinstate Monica and @RbMm in the comments.
At first I thought I needed my timestamps to be in local time because my events had local time timestamps, but after further reading of the Microsoft docs, I found that my events have UTC timestamps. (If anyone is interested, more details about the events I am trying to process can be found in this question.)
GetSystemTimePreciseAsFileTime()
returns a timestamp in UTC, and so I don't need to perform any conversion.