In my system I have a PC (Linux, in case it matters) which keeps RTC time in UTC, making my localtime timezone specific. In PC code, I get UTC time as seconds since epoch using
struct timespec tv;
clock_gettime(CLOCK_REALTIME, &tv);
double time = (tv.tv_nsec / 1000000000.0) + tv.tv_sec;
return time;
I also have a 3rd party network device which provides its time also as seconds from epoch, but it does so using localtime instead of UTC time. This is a problem because, when I print the two timestamps in an interleaved log with timestamps from PC and this device, even though the two clocks show the same localtime, the timestamps are off.
Let's assume that the timezone settings (UTC offset and daylight savings specifications) are the same between the PC and this device. How would I take the seconds since epoch provided by the device (in localtime) and convert it to seconds since epoch in UTC? In other words, what the programmatic (in C) way to apply PC timezone settings to a seconds since epoch when that number is in localtime?
Here is my attempt at converting the 3rd party device localtime based seconds since epoch to UTC based seconds since epoch.
#include <stdio.h>
#include <time.h>
int main(void)
{
// The following epoch timestamps were converted to human time via https://www.epochconverter.com/
time_t device_rawtime = 1568133906.065000; // if treated as GMT: Tuesday, September 10, 2019 4:45:06.065 PM
time_t pc_rawtime = 1568151907.454432; // if treated as localtime: Tuesday, September 10, 2019 4:45:07.454 PM GMT-05:00 DST
struct tm ts;
char buf[80];
ts = *gmtime(&device_rawtime);
strftime(buf, sizeof(buf), "%a %Y-%m-%d %H:%M:%S %Z", &ts);
time_t converted = mktime(&ts);
printf("Device rawtime=%ld which is PC localtime %s ==> UTC based rawtime=%ld (pc was %ld)\n", device_rawtime, buf, converted, pc_rawtime);
return 0;
}
The above does not work. It prints
Device rawtime=1568133906 which is PC localtime Tue 2019-09-10 16:45:06 GMT ==> UTC based rawtime=1568155506 (pc was 1568151907)
As you can see, the converted device timestamp does not equal PC timestamp. How should this be done?
The relevant information is found in
man mktime
:On return from
gmtime(&device_rawtime)
, ts.tm_isdst is set to zero, since UTC taken bygmtime()
is never daylight saving. So, whenmktime(&ts)
is called, it converts the time structure with the information that DST is not in effect, thus we get a converted time value which is 3600 seconds too high. To correctly account for DST, settingbefore calling
mktime(&ts)
is sufficient.