Создание объекта boost :: posix_time :: ptime из 64-битного целого числа секунд

У меня есть 32-битная система Linux, в которой я должен записывать данные с меткой времени с секундным смещением UINT32 от эпохи 1901-01-01 00:00:00.

расчета временная метка мне подходит, так как я могу использовать 64 бит ticks() счетчик и ticks_per_second() функции для генерации секунд, начиная с эпохи, следующим образом (мне требуется только разрешение второго уровня)

const ptime ptime_origin(time_from_string("1901-01-01 00:00:00"));
time_duration my_utc = microsec_clock::universal_time() - ptime_origin;
boost::int64_t tick_per_sec = my_utc.ticks_per_second();
boost::int64_t tick_count = my_utc.ticks();
boost::int64_t sec_since_epoch = tick_count/tick_per_sec;

Это работает для меня, так как я знаю, что как целое число без знака, количество секунд не будет превышать максимальное значение UINT32 (ну, во всяком случае, не на много лет).

У меня проблема в том, что мое приложение может получить сообщение Modbus, содержащее значение UINT32, для которого я должен установить аппаратные и системные часы с помощью ioctl звоните используя RTC_SET_TIME, Этот UINT32 снова является смещением в секундах с моей эпохи 1901-01-01 00:00:00.

Моя проблема сейчас в том, что у меня нет возможности Создайте ptime объект, использующий 64-битные целые числа — ticks часть time_duration объекты являются частными, и я ограничен в использовании long которая в моей 32-битной системе представляет собой 4-байтовое целое число со знаком, недостаточно большое для хранения смещения секунд от моей эпохи.

Я не имею никакого контроля над ценностью эпохи, и поэтому я действительно озадачен тем, как я могу создать свой требуемый boost::posix_time::ptime объект из данных у меня есть.
Вероятно, я могу получить грязное решение, рассчитав счетчик жестких секунд для определенных временных интервалов и используя дополнительную эпоху, чтобы сделать мост, чтобы позволить это, но мне было интересно, есть ли что-то в boost код, который позволит мне полностью решить проблему с помощью библиотеки datetime boost.
Я прочитал всю документацию, которую могу найти, но не вижу никакого очевидного способа сделать это.

РЕДАКТИРОВАТЬ: я нашел этот связанный вопрос Конвертировать int64_t в time_duration но принятый ответ там не работает для моей эпохи

5

Решение

Вы могли бы применить time_durations в максимально допустимых приращениях (что std::numeric_limits<long>::max()) так как total_seconds поле ограничено long (Подпись).

Заметка: Я сформулировал это как int32_t ниже, чтобы он все равно работал правильно, если скомпилирован на 64-битной платформе.

Вот небольшая демонстрация:

#include "boost/date_time.hpp"#include <iostream>

using namespace boost::gregorian;
using namespace boost::posix_time;

int main()
{
uint64_t offset = 113ul*365ul*24ul*60ul*60ul; // 113 years give or take some leap seconds/days etc.?

static const ptime time_t_epoch(date(1901,1,1));
static const uint32_t max_long = std::numeric_limits<int32_t>::max();
std::cout << "epoch: " << time_t_epoch << "\n";

ptime accum = time_t_epoch;
while (offset > max_long)
{
accum  += seconds(max_long);
offset -= max_long;
std::cout << "accumulating: " << accum << "\n";
}

accum += seconds(offset);
std::cout << "final: " << accum << "\n";
}

Печать:

epoch: 1901-Jan-01 00:00:00
accumulating: 1969-Jan-19 03:14:07
final: 2013-Dec-04 00:00:00

Видеть это Жить на Колиру

2

Другие решения

Хотя boost::posix_time::seconds не могу использоваться, если секунды представляют число больше 32 бит (по состоянию на октябрь 2014 г.), получается, что boost::posix_time::milliseconds Можно легко использовать (без обходных путей), а именно:

inline std::string convertMsSinceEpochToString(std::int64_t const ms)
{
boost::posix_time::ptime time_epoch(boost::gregorian::date(1970, 1, 1));
boost::posix_time::ptime t = time_epoch + boost::posix_time::milliseconds(ms);
return boost::posix_time::to_simple_string(t);
}

Итак, просто преобразуйте свои 64-битные секунды в (64-битные) миллисекунды, и все готово!


Заметка Быть / очень / знать о зависимом от компилятора поведении с возможностью создания целочисленных типов:

uint64_t offset = 113ul*365ul*24ul*60ul*60ul*1000ul; // 113 years give or take some leap seconds/days etc.?

будет работать на GCC или Clang, но это просто переполнит вычисления в MSVC2013. Вам нужно было бы явно привести вычисление к 64 битам:

uint64_t offset = uint64_t(113ul)*365*24*60*60*1000;
2