Преобразование десятичного времени GPS в UTC

Есть много подобных вопросов, но я не нашел ни одного конкретного для выходных данных GPS, которые я получаю. Данные моего GPS представлены в десятичной форме:

Неделя GPS: 2145 и Время GPS: 330374.741371 (в руководстве говорится, что это двойное число, представляющее время недели в секундах)

Я пытаюсь преобразовать это время в удобочитаемое время UTC. Я использую старый С++ 14, а не 20, поэтому я не могу просто использовать функцию to_utc(), я не думаю. Меня больше всего смущает десятичная дробь. На этом веб-сайте: https://www.labsat.co.uk/index.php/en/gps-time-calculator похоже, что данные представляют собой secondOfTheWeek.secondsOfTheDay. Я не уверен, как преобразовать это время в UTC...

Я полагаю, что эти выходные данные представляют собой количество секунд, прошедших со времени эпохи GPS в полночь 6 января 1980 года. И я знаю, что они не учитывают високосные секунды, поэтому это также необходимо учитывать. Если бы у меня было какое-то руководство о том, как начать переводить это во время UTC, я думаю, я мог бы понять остальное, но я не совсем уверен, с чего начать...

В конце концов я хочу преобразовать время в строку, чтобы установить систему ОС с этим временем, используя date -s 16 AUG 2021 13:51:00 или что-то в этом роде. Но сначала мне просто нужно преобразовать это время GPS.


person Two Bits    schedule 28.04.2021    source источник
comment
У вас есть несколько советов по обновлению номера недели GPS. Введите даты пролонгации в калькулятор, который вы показали, и это должно быть возможно выяснить.   -  person Ted Lyngmo    schedule 29.04.2021


Ответы (1)


Существует бесплатная предварительная версия с открытым исходным кодом для C++20 хронобит, которая работает с C+. +14.

#include "date/tz.h"
#include <chrono>

date::utc_seconds
convert(int gps_week, double gps_time)
{
    using namespace date;
    using namespace std::chrono;

    int upper = static_cast<int>(gps_time);
    auto gps_t = gps_seconds{} + weeks(gps_week) + seconds{upper};
    return clock_cast<utc_clock>(gps_t);
}

Это сначала формирует gps_time, добавляя соответствующее количество недель к эпохе GPS, а затем секунды.

Затем вы используете clock_cast, чтобы преобразовать это в utc_time (которое действительно включает дополнительные секунды).

Это можно использовать так:

#include <iostream>

int
main()
{
    using namespace date;
    using namespace std;

    cout << convert(2145, 330374.741371) << '\n';
}

Что выводит:

2021-02-17 19:45:56

clock_cast изменяет эпоху с 1980-01-06 на 1970-01-01 и добавляет количество високосных секунд, которые происходят между эпохой GPS и точкой времени UTC. Если ввод GPS соответствует дополнительной секунде, в поле секунд будет правильно напечатано 60. Например:

cout << convert(1851, 259216) << '\n';  // 2015-06-30 23:59:60

Требуется некоторая установка.

Дальнейшая информация

В этой статье Википедии говорится, что время недели на самом деле указывается в единицах 1,5 секунды, начиная в значении от 0 до 403 199.

static_assert(403'200 * 1.5 == 7 * 24 * 60 * 60);

Если вы обнаружите, что имеете дело с данными в этой форме, вот альтернативная реализация convert, которая может напрямую обрабатывать эти входные данные:

using gps_tow = std::chrono::duration<int, std::ratio<3, 2>>;

auto
convert(date::weeks gps_week_num, gps_tow tow)
{
    using namespace date;
    return clock_cast<utc_clock>(gps_seconds{} + gps_week_num + tow);
}

Первым шагом является определение единицы продолжительности 1,5 секунды. Этот тип называется gps_tow выше.

Функция convert теперь принимает два строго типизированных параметра: количество weeks и количество gps_tow. Затем нужно просто сложить эти части вместе с эпохой GPS и clock_cast получить utc_clock.

Его можно использовать так:

cout << convert(weeks{1851}, gps_tow{172811}) << '\n';

Вывод для этого примера:

2015-06-30 23:59:60.5
person Howard Hinnant    schedule 28.04.2021