C++ получить миллисекунды с 01/01/0101 00:00:00

Мне нужна временная метка в специальном формате для вызова API:

Даты преобразуются в миллисекунды UTC, прошедшие с 12:00:00 до полуночи 1 января 0001 года.

Мое первое предположение было использовать:

auto now = std::chrono::system_clock::now();
std::cout << "millisceconds since epoch: "
          << std::chrono::duration_cast<std::chrono::milliseconds>(
               now.time_since_epoch()).count() 

Но, конечно же, вывод - это временной интервал с эпохи UNIX Thu Jan 1 00:00:00 1970

Так что для now = "Wed Dec 12 13:30:00 2018" это возвращается 1544617800000Миз.

Как получить миллисекунды с 12:00:00 до полуночи 1 января 0001 года?

Контекст OSISoft API

Документация API OSISoft для указания диапазона дат довольно странная

Числовой диапазон запросов

Предыдущими примерами были Range Queries против строковых полей. Числовые значения> также можно искать с помощью Range Queries.

Единственными полями, которые проиндексированы как числовые поля, являются поля CreationDate и ChangeDate для соответствующих атрибутов PI Point. Для индексации этих полей> добавьте их в список атрибутов PI Point. Эту конфигурацию можно просмотреть> или изменить на странице настроек.

Эти значения даты и времени индексируются как числовые значения посредством преобразования: даты преобразуются в миллисекунды UTC, прошедшие с 12:00:00 до полуночи 1 января 0001 года.

В следующем примере запрос представляет собой запрос на дату последнего изменения, равную или> превышающую 26 февраля, 22:16:50.000 (это всемирное время). Этот DateTime, после вышеупомянутого преобразования, будет представлен как числовое значение: 63655280210000. Поэтому отправленный запрос:

https://MyServer/piwebapi/search/query?q=changedate:[63655280210000 TO *]

Из этой документации я задал этот вопрос о том, как получить миллисекунды с 12:00:00 до полуночи 1 января 0001 года.

Я также связал вопрос с PISquare

2 ответа

Решение

Не существует определенного способа расчета:

UTC миллисекунды истекли с 12:00:00 до полуночи 1 января 0001 года.

Судя по примерам, они используют тот же алгоритм, что и https://www.epochconverter.com/seconds-days-since-y0. Чтобы получить тот же результат, вы можете просто добавить 719162 дней в эпоху Unix:

auto now = std::chrono::system_clock::now();
std::cout << "millisceconds since epoch: "
          << std::chrono::duration_cast<std::chrono::milliseconds>(
               now.time_since_epoch() + std::chrono::hours(24 * 719162)).count()

Примечание C++20 вводит std::chrono::days который вы могли бы использовать вместо 24 часов. В зависимости от разрешения системных часов вам может потребоваться привести в миллисекунды перед добавлением смещения, чтобы избежать переполнения (719162 дней - это более 2^64 наносекунд).

Это легко, используя библиотеку даты / времени Говарда Хиннанта:

#include "date/date.h"
#include <iostream>

std::chrono::milliseconds
convert(std::chrono::system_clock::time_point tp)
{
    using namespace date;
    using namespace std::chrono;
    return (floor<milliseconds>(tp) + 
            (sys_days{1970_y/January/1} - sys_days{1_y/January/1})).time_since_epoch();
}

int
main()
{
    using namespace date;
    using namespace std::chrono;
    std::cout << convert(system_clock::now()) << '\n';
}

convert просто добавляет разницу между двумя эпохами к system_clock::time_pointусеченный до milliseconds точность, и извлекает duration вернуть его как milliseconds,

Эта программа для меня просто вывод:

63680221359193ms

Диапазон на milliseconds достаточно большой, чтобы справиться с этим вычислением, но диапазон на вашем system_clock::time_point может не быть. Таким образом, важно усечь milliseconds сразу как сделано в коде выше, чтобы избежать переполнения.

Другие вопросы по тегам