如何在 C++ 中将 gps 时间转换为 utc?

How to convert gps time to utc in c++?

我正在从传感器收集 GPS 时间(以 ns 为单位),我正在寻找一种方法将其转换为 C++ 中的 UTC 时间。

我之前在 python 中有一个工作代码。

    time_gps = time_gps * 10**(-9)    # Converts ns -> s
    gps_epoch = pd.datetime(year=1980, month=1, day=6)
    delta = pd.to_timedelta(time_gps, unit='s')
    time = gps_epoch + delta - pd.to_timedelta(19, unit='s')

使用 link“”帮助我了解如何将 GPS 时间转换为 UTC。

    uint64_t gps_input_ns = 1281798087485516800;         
    date::gps_time<std::chrono::nanoseconds> gt_nano{date::round<std::chrono::nanoseconds>(std::chrono::duration<uint64_t, std::nano>{gps_input_ns})};
    auto utc_nano = date::clock_cast<date::utc_clock>(gt_nano);
    std::cout << utc_nano << " UTC\n";
Output: 2020-08-18 15:01:09.485516800 UTC

我的下一个问题是,如何从变量“utc_nano”中提取日期和时间?我对 chrono 或日期库不是很熟悉,因此在尝试分隔日期和时间时遇到问题。任何帮助将不胜感激。

我假设闰秒对你很重要,因为你正在处理 gps 时间,它代表物理秒数,UTC 标记为闰秒。用闰秒来操纵 date/times 是相当棘手的,这就是 Unix Time 在计算机系统中如此流行的原因。

C++20 计时预览库 中,Unix Timesys_time 建模,而真正的 UTC 由 utc_time 建模.这两个模型之间的唯一区别是 sys_time 不计算闰秒而 utc_time 计算闰秒。

sys_time 的优点是存在一种快速有效的算法,可以将自 1970-01-01 00:00:00 以来的持续时间转换为以下字段:年、月、日、小时、分钟,秒,亚秒。所以如果你想把 utc_time 分成这些字段,诀窍是首先把 utc_time 变成 sys_time,同时记住你的 utc_time 是否引用闰秒。事实上,这正是 utc_time 的流式运算符所做的。

有一个辅助函数 get_leap_second_info 可以帮助完成这项工作。这个函数接受一个 utc_time 和 returns 一个 {is leap second, count of leap seconds} 结构。如果参数指的是闰秒,则第一个成员为真,第二个参数告诉您参数和 1970 之间有多少闰秒。所以第一步是获取 utc_nano 的信息:

auto info = get_leap_second_info(utc_nano);

现在您可以使用此信息创建 sys_time。因为 sys_time 就像 utc_time 不包括闰秒,你可以减去已发生的闰秒数:

sys_time<nanoseconds> sys_nano{utc_nano.time_since_epoch() - info.elapsed};

现在您在 Unix Time 中得到了纳秒数。截断到 days 精度可以得到 Unix Time:

中的天数
auto sys_day = floor<days>(sys_nano);

sys_day 是一个日期。一天中的时间只是 nanoseconds-precision time_point 和 days-precision time_point:

之间的差异
auto tod = sys_nano - sys_day;

tod是一次。这是自午夜以来的持续时间。它可能会短一秒钟。该信息位于 info.is_leap_second.

如果您希望这些类型作为“字段类型”,您可以将 sys_day 转换为类型 year_month_day:

year_month_day ymd = sys_days;

year_month_dayyearmonthday.

的吸气剂

您可以将 tod 转换为 {hours, minutes, seconds, nanoseconds} 结构:

hh_mm_ss hms{tod};

这有吸气剂:hours()minutes()seconds()subseconds()。上面的语法假定 C++17。如果在 C++11 或 14 中,语法为:

hh_mm_ss<nanoseconds> hms{tod};

hh_mm_ss 不直接支持 60 秒的计数,但该信息仍在 info.is_leap_second 中。例如

std::cout << hms.seconds().count() + info.is_leap_second << '\n';

当且仅当 info.is_leap_second 为真时才会输出 60。

您甚至可以尝试使用 C 时间相关函数的代码

uint64_t ns = 1281798087485516800ULL + 315964800000000000ULL; // offset between gps epoch and unix epoch is 315964800 seconds

struct timespec ts;
ts.tv_sec = ns / 1000000000ULL;
ts.tv_nsec = ns % 1000000000ULL;

struct tm stm;
gmtime_r(&ts.tv_sec, &stm);
std::cout << stm.tm_year + 1900 << "-" << stm.tm_mon + 1 << "-" << stm.tm_mday << " " << stm.tm_hour << ":" << stm.tm_min << ":" << stm.tm_sec << std::endl;