【问题标题】:How to convert gps time to utc in c++?如何在c ++中将gps时间转换为utc?
【发布时间】:2020-12-07 22:26:32
【问题描述】:

我正在从传感器收集 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')

使用链接“Using std::chrono / date::gps_clock for converting a double gps timestamp to utc/tai”帮助我弄清楚如何将 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 或日期库不是很熟悉,因此在尝试分离日期和时间时遇到了问题。任何帮助将不胜感激。

【问题讨论】:

  • 注意重复,但信息丰富:Using std::chrono / date::gps_clock for converting a double gps timestamp to utc/tai。再三考虑,如果您选择走chrono 路线,可能会重复。
  • 您能否更具体地了解“get”?您想要的结果是终端上的输出还是字符串?或者你想要分别代表日期和时间的计时类型?换句话说,这是一个格式问题还是一个数据结构问题?
  • @HowardHinnant 我将我的问题编辑得更具体一点,希望它能回答您的问题。我所说的“get”是指从变量“utc_nano”中提取日期和时间。

标签: c++ c++11 gps utc data-conversion


【解决方案1】:

我假设闰秒对您很重要,因为您正在处理 gps 时间,它表示由 UTC 标记为闰秒的物理秒数。使用闰秒来操作日期/时间是相当棘手的,这就是Unix Time 在计算机系统中如此受欢迎的原因。

C++20 chrono preview library 中,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 并返回 {is leap second, count of leap seconds} 结构。如果参数引用闰秒,则第一个成员为真,第二个参数告诉您从参数到 1970 年之间有多少闰秒。所以第一步是获取 utc_nano 的此信息:

auto info = get_leap_second_info(utc_nano);

现在您可以使用此信息创建sys_time。由于sys_timeutc_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 是一个日期。一天中的时间只是纳秒精度 time_point 和天精度 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。

【讨论】:

  • 感谢您的帮助!所以我的方法不同,但步骤相似。 - 我通过使用clock_cast 获得了sys_time:auto utc_sys = clock_cast&lt;system_clock&gt;(utc_nano)。 - 然后我通过使用auto utc_dp = date::floor&lt;date::days&gt;(utc_sys) 获得了 sys_days。 - 为了获取日期,我使用了 year_month_day:auto ymd = year_month_day{utc_dp} - 而我使用了 make_time:auto time = make_timeduration_cast&lt;nanoseconds&gt;(utc_sys-utc_dp))。 - 然后我使用你提到的 getter 来格式化我的日期和时间。
  • 除闰秒外有效。如果您从闰秒期间的 GPS 时间开始,clock_castsys_time 将落在闰秒之前的最后一个可表示时刻。所以日期是正确的,时间是 23:59:59.999...
【解决方案2】:

您甚至可以尝试使用 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;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-17
    • 1970-01-01
    相关资源
    最近更新 更多