首页 > 解决方案 > 将自纪元以来的本地时间(以秒为单位)转换为 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 时间戳。这应该怎么做?

标签: cdatetimeutclocaltimetimespec

解决方案


我同意这可能是由于夏令时。但问题是我应该如何解释这一点?

相关信息见man mktime

tm_isdst字段中指定的值通知mktime () 对于tm结构中提供的时间,夏令时 (DST) 是否有效:正值表示 DST 有效;零表示 DST 无效;而负值意味着mktime () 应该(使用时区信息和系统数据库来)尝试确定 DST 在指定时间是否有效。

从 返回时gmtime(&device_rawtime), ts.tm_isdst 设置为零,因为采用的 UTCgmtime()绝不是夏令时。因此,当mktime(&ts)被调用时,它将时间结构与DST 无效的信息进行转换,因此我们得到的转换时间值 3600 秒太高了。为了正确考虑 DST,设置

ts.tm_isdst = -1

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


推荐阅读