将自纪元以来以秒为单位的本地时间转换为 UTC

Convert localtime in seconds since epoch to UTC

在我的系统中,我有一台 PC(Linux,以防万一),它将 RTC 时间保持为 UTC,使我的本地时间成为特定时区。在 PC 代码中,我使用

获得自纪元以来的秒数 UTC 时间
struct timespec tv; 
clock_gettime(CLOCK_REALTIME, &tv);
double time = (tv.tv_nsec / 1000000000.0) + tv.tv_sec;
return time;

我还有一个第 3 方网络设备,它提供的时间也是从纪元算起的秒数,但它使用的是本地时间而不是 UTC 时间。这是一个问题,因为当我在交错日志中打印两个时间戳以及来自 PC 和此设备的时间戳时,即使两个时钟显示相同的本地时间,时间戳也已关闭。

假设 PC 和此设备的时区设置(UTC 偏移和夏令时规范)相同。我如何使用设备提供的纪元以来的秒数(本地时间)并将其转换为 UTC 纪元以来的秒数?换句话说,当该数字在本地时间时,将 PC 时区设置应用于自纪元以来的秒数的编程(C 语言)方式是什么?

这是我尝试将第 3 方设备自纪元以来基于本地时间的秒数转换为自纪元以来基于 UTC 的秒数。

#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;
}

以上方法无效。它打印

Device rawtime=1568133906 which is PC localtime Tue 2019-09-10 16:45:06 GMT ==> UTC based rawtime=1568155506 (pc was 1568151907)

如您所见,转换后的设备时间戳不等于PC时间戳。应该怎么做?

I agree that it's likely due to daylight savings. But the question is how should I be accounting for that?

相关资料见man mktime:

The value specified in the tm_isdst field informs mktime() whether or not daylight saving time (DST) is in effect for the time supplied in the tm structure: a positive value means DST is in effect; zero means that DST is not in effect; and a negative value means that mktime() should (use timezone information and system databases to) attempt to determine whether DST is in effect at the specified time.

gmtime(&device_rawtime) 的 return 上,ts.tm_isdst 设置为零,因为 gmtime() 使用的 UTC 从不采用夏令时。所以,当mktime(&ts)被调用时,它转换了时间结构与夏令时无效的信息,因此我们得到一个转换后的时间值,这个值是3600秒太高了。要正确计算夏令时,设置

ts.tm_isdst = -1

在调用mktime(&ts)之前就足够了。