Что заставляет мои функции, связанные с ctime c ++, вести себя странно? - PullRequest
0 голосов
/ 05 апреля 2019

Я сделал две функции, которые должны вычислять начальную временную метку дня (т.е. в 00:00:00 дня) и час (начиная с 1 и до 24) данной временной метки эпохи.

#include <cstdint>
#include <ctime>

const uint8_t FIRST_HOUR = 0x01;  // 01, 02, ..., 24
const uint32_t SECS_PER_HOUR = 3600;  // 3600 secs per hour

uint32_t CalcDaiBaseTimestamp(uint32_t in_ts) {
  time_t ts = in_ts;
  struct tm timeinfo = *localtime(&ts);
  timeinfo.tm_hour = 0;
  timeinfo.tm_min = 0;
  timeinfo.tm_sec = 0;
  time_t tmp_base_ts = mktime(&timeinfo);

  return (uint32_t)tmp_base_ts;
}

void CalcDaiBaseTimestampAndHour(uint32_t in_ts,
                                 uint32_t& base_ts,
                                 uint8_t& hour_nth) {
  base_ts = CalcDaiBaseTimestamp(in_ts);
  hour_nth = (in_ts - base_ts) / SECS_PER_HOUR + FIRST_HOUR;
}

CalcDaiBaseTimestampAndHour вызывается из нескольких потоков.

Код скомпилирован с g++ (Ubuntu 4.8.4-2ubuntu1~14.04.4) 4.8.4, а программа работает на Ubuntu 14.04 x64.

Большую часть времени моя программа работает хорошо, но я иногда наблюдал некоторые «странные» результаты, как показано ниже:

(timestamp: 1554459477.500) -> (base: 1553990400, hour_nth: 131)

Пока правильный результат должен быть:

(timestamp: 1554459477.500) -> (base: 1554422400 / hour_nth: 11)

Потому что:

1554459477.500 = 2019-04-05 10:17:57.500
base_ts = 2019-04-05 00:00:00 = 1554422400
hour_nth = 11

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

Что может вызвать "странные" результаты? Пожалуйста, помогите мне решить эту проблему! Если на самом деле причина в поточной безопасности функций, связанных с ctime, то как я могу обойти эту проблему (например, с помощью некоторой стандартной библиотеки C ++ 11)?

1 Ответ

3 голосов
/ 05 апреля 2019

Не могли бы вы показать мне, как обойти это с помощью библиотеки дат?

Ссылка: https://github.com/HowardHinnant/date

Код:

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

int
main()
{
    using namespace std::chrono;
    using namespace date;
    using dsec = duration<double>;
    sys_time<dsec> tp{dsec{1554459477.500}};
    std::cout << std::setprecision(3) << std::fixed
              << tp.time_since_epoch().count()
              << " = " << round<milliseconds>(tp) << '\n';
    sys_seconds base_ts = floor<days>(tp);
    std::cout << "base_ts = " << base_ts << " = "
              << base_ts.time_since_epoch().count() << '\n';
    auto hour_nth = floor<hours>(tp - base_ts) + hours{1};
    std::cout << "hour_nth = " << hour_nth.count() << '\n';
}

Выход:

1554459477.500 = 2019-04-05 10:17:57.500
base_ts = 2019-04-05 00:00:00 = 1554422400
hour_nth = 11

Примечания:

  • Здесь нет проблем с безопасностью потоков.
  • Пока вам не нужна поддержка часовых поясов, «date / date.h» - это библиотека с одним заголовком, только для заголовка.
  • Все выше, UTC.
  • Документация: https://howardhinnant.github.io/date/date.html
...