Использование библиотеки chrono C++ для вычисления разницы временных меток

Следуя здесь

Я пытаюсь увидеть, являются ли мои данные 120-секундными или нет, глядя на метку времени данных, поэтому у меня есть небольшой код в моем проекте библиотеки, который использует пакет std::chrono:

uint64_t now = duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();
bool is_old = (120 * 1000 < (now - data_holder->getTimestamp()));

// some logging to print out above values
LOG4CXX_WARN(logger, "data logging, now: " << now << ", data holder timestamp: " << data_holder->getTimestamp() << ", is_old: " << is_old << ", difference: " << (now -         data_holder->getTimestamp()));

В приведенном выше коде data_holder->getTimestamp() равно uint64_t, который возвращает отметку времени в миллисекундах.

Теперь, когда я распечатываю значение переменной now, я вижу это 433425679, а когда я распечатываю значение data_holder->getTimestamp(), которое равно 1437943796841, разница между текущим временем и временной меткой держателя данных составляет 18446742636199180454, как показано ниже в журналах:

2015-07-26 13:49:56,850 WARN 0x7fd050bc9700 simple_process - data logging, now: 433425679 , data holder timestamp: 1437943796841 , is_old: 1 , difference: 18446742636199180454

Теперь, если я конвертирую временную метку держателя данных 1437943796841 с помощью конвертера эпох, я вижу это:

Your time zone: 7/26/2015, 1:49:56 PM

что точно совпадает с отметкой времени, показанной в журналах 2015-07-26 13:49:56,850 WARN, так что это означает, что мои данные не выглядят как данные 120-секундной давности. Если да, то почему я вижу значение is_old как 1?

Похоже, что значение data_holder->getTimestamp() исходит из приведенного ниже кода в нашей кодовой базе, а затем мы сравниваем его для проверки 120-секундных старых данных.

// is this the problem?
struct timeval val;
gettimeofday(&val, NULL);
uint64_t time_ms = uint64_t(val.tv_sec) * 1000 + val.tv_usec / 1000;

Теперь, внимательно прочитав о различных реализациях часов в C++, похоже, что мы должны использовать одни и те же часы для сравнения.

Является ли мой приведенный выше код, в котором я вычисляю значение data_holder->getTimestamp(), проблемой? так как я не использую steady_clock, поэтому время эпохи будет другим, и поэтому я вижу эту проблему?

Теперь мой вопрос: какой код я должен использовать, чтобы решить эту проблему? Должен ли я также использовать steady_clock для кода data_holder->getTimestamp()? Если да, то как правильно?

Также тот же код отлично работает в Ubuntu 12, но не работает в Ubuntu 14. Я запускаю все статически связанные библиотеки. Для Ubuntu 12 код компилируется в Ubuntu 12 с компилятором 4.7.3, а для Ubuntu 14 код компилируется в Ubuntu 14 с компилятором 4.8.2.


person user1950349    schedule 20.08.2015    source источник
comment
std::chrono::steady_clock не связан со временем настенных часов (std::chrono::system_clock). Другими словами, вы не можете сравнивать время по постоянным часам со временем по системным (настенным) часам. А gettimeofday возвращает время настенных часов.   -  person Some programmer dude    schedule 20.08.2015
comment
Ясно, тогда что нам здесь делать? Любой из этих двух кодов изменится, я думаю, верно?   -  person user1950349    schedule 20.08.2015


Ответы (2)


Вы определенно должны использовать одну и ту же функцию времени для обоих.

Я бы рекомендовал изменить либо способ создания значения getTimestamp() (например, с помощью chrono::system_clock), либо способ сравнения метки времени.

Чистым способом было бы изменить его следующим образом:

struct timeval val;
gettimeofday(&val, NULL);
uint64_t now = uint64_t(val.tv_sec) * 1000 + val.tv_usec / 1000;
bool is_old = (120 * 1000 < (now - data_holder->getTimestamp()));

Или наоборот

1. Измените способ создания значения getTimestamp().

long long time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();

2. Настройте функцию сравнения

long long now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
bool is_old = (120 * 1000 < (now - data_holder->getTimestamp()));
person Simon Kraemer    schedule 20.08.2015

Используйте одни и те же часы для обоих. Если ваши временные метки должны сохранять значение при выполнении вашего приложения, вы должны использовать system_clock, а не steady_clock. Если ваши временные метки имеют значение только в рамках одного запуска, вы можете использовать steady_clock.

steady_clock похож на "секундомер". Вы можете измерять время с его помощью, но вы не можете получить текущее время дня с его помощью.

DataHolder::DataHolder()
    : timestamp_{system_clock::now()}
    {}

system_clock::time_point
DataHolder::getTimestamp()
{
    return timestamp_;
}

bool is_old = minutes{2} < system_clock::now() - data_holder->getTimestamp();

В С++ 14 вы можете сократить это до:

bool is_old = 2min < system_clock::now() - data_holder->getTimestamp();

  • Используйте <chrono>.
  • Не используйте count() или time_since_epoch() (за исключением целей отладки).
  • Не используйте коэффициенты преобразования, такие как 1000 или 120.

Нарушение приведенных выше рекомендаций превратит ошибки времени компиляции в ошибки времени выполнения. Ошибки времени компиляции — ваш друг. <chrono> выявляет множество ошибок во время компиляции. Как только вы избегаете безопасности типов <chrono> (например, используя count()), вы программируете на ассемблере эквивалент хронометража. А затраты пространства/времени на систему безопасности типов <chrono> равны нулю.

person Howard Hinnant    schedule 20.08.2015