C++ как преобразовать std:: chrono:: time point в long и обратно
мне нужно, чтобы преобразовать std::chrono::time_point
и long
тип (целое число 64 бита). Im, начиная работать с std::chrono
...
вот мой код:
int main ()
{
std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
auto epoch = now.time_since_epoch();
auto value = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);
long duration = value.count();
std::chrono::duration<long> dur(duration);
std::chrono::time_point<std::chrono::system_clock> dt(dur);
if (dt != now)
std::cout << "Failure." << std::endl;
else
std::cout << "Success." << std::endl;
}
этот код компилируется, но не показывает успехов.
почему dt
другое, чем now
в конце?
чего не хватает в этом коде?
3 ответов
std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
это отличное место для auto
:
auto now = std::chrono::system_clock::now();
так как вы хотите, чтобы трафик на millisecond
точность, было бы хорошо пойти вперед и скрыться к нему в time_point
:
auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);
now_ms
это time_point
на основе system_clock
, но с точностью milliseconds
вместо любой точности вашего system_clock
есть.
auto epoch = now_ms.time_since_epoch();
epoch
теперь имеет тип std::chrono::milliseconds
. И это следующее утверждение становится по существу no-op (просто делает копию и не делает преобразования):
auto value = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);
здесь:
long duration = value.count();
в вашем и моем коде,duration
содержит количество milliseconds
С эпохи system_clock
.
это:
std::chrono::duration<long> dur(duration);
создает duration
представлен long
, и точностью seconds
. Это эффективно reinterpret_cast
s milliseconds
проведено в value
to seconds
. Это логическая ошибка. Правильный код будет выглядеть так:
std::chrono::milliseconds dur(duration);
этот строка:
std::chrono::time_point<std::chrono::system_clock> dt(dur);
создает time_point
на основе system_clock
, С возможностью держать точность к system_clock
собственная точность (обычно тоньше миллисекунд). Однако значение времени выполнения будет правильно отражать, что целое число миллисекунд удерживается (при условии моей коррекции по типу dur
).
даже с коррекцией, этот тест (почти всегда) потерпит неудачу, хотя:
if (dt != now)
, потому что dt
содержит Интеграл количество milliseconds
, а now
содержит целое число тиков тоньше, чем millisecond
(например,microseconds
или nanoseconds
). Таким образом, только на редкий случай, что system_clock::now()
возвращает целое число milliseconds
пройдет ли тест.
но вы можете вместо этого:
if (dt != now_ms)
и теперь вы получите ожидаемый результат надежно.
собираем все вместе:
int main ()
{
auto now = std::chrono::system_clock::now();
auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);
auto value = now_ms.time_since_epoch();
long duration = value.count();
std::chrono::milliseconds dur(duration);
std::chrono::time_point<std::chrono::system_clock> dt(dur);
if (dt != now_ms)
std::cout << "Failure." << std::endl;
else
std::cout << "Success." << std::endl;
}
лично я нахожу все std::chrono
излишне многословным, и поэтому я бы код это как:
int main ()
{
using namespace std::chrono;
auto now = system_clock::now();
auto now_ms = time_point_cast<milliseconds>(now);
auto value = now_ms.time_since_epoch();
long duration = value.count();
milliseconds dur(duration);
time_point<system_clock> dt(dur);
if (dt != now_ms)
std::cout << "Failure." << std::endl;
else
std::cout << "Success." << std::endl;
}
который будет надежно выводить:
Success.
наконец, я рекомендую исключить временные, чтобы уменьшить преобразование кода между time_point
и интегральный тип к минимуму. Эти преобразования опасны, и поэтому чем меньше кода Вы пишете, манипулируя голым интегральным типом, тем лучше:
int main ()
{
using namespace std::chrono;
// Get current time with precision of milliseconds
auto now = time_point_cast<milliseconds>(system_clock::now());
// sys_milliseconds is type time_point<system_clock, milliseconds>
using sys_milliseconds = decltype(now);
// Convert time_point to signed integral type
auto integral_duration = now.time_since_epoch().count();
// Convert signed integral type to time_point
sys_milliseconds dt{milliseconds{integral_duration}};
// test
if (dt != now)
std::cout << "Failure." << std::endl;
else
std::cout << "Success." << std::endl;
}
главная опасность выше не перевод integral_duration
as milliseconds
на обратном пути к time_point
. Один из возможных способов смягчить этот риск-написать:
sys_milliseconds dt{sys_milliseconds::duration{integral_duration}};
это снижает риск, только убедившись, что вы используете sys_milliseconds
на выходе и в двух местах на обратном пути.
и еще один пример: Предположим, вы хотите преобразовать в Интеграл и из интеграла, который представляет любую длительность system_clock
поддержка (микросекунды, 10th микросекунд или наносекунд). Тогда вам не нужно беспокоиться об указании миллисекунд, как указано выше. Этот код упрощается до:
int main ()
{
using namespace std::chrono;
// Get current time with native precision
auto now = system_clock::now();
// Convert time_point to signed integral type
auto integral_duration = now.time_since_epoch().count();
// Convert signed integral type to time_point
system_clock::time_point dt{system_clock::duration{integral_duration}};
// test
if (dt != now)
std::cout << "Failure." << std::endl;
else
std::cout << "Success." << std::endl;
}
это работает, но если вы запустите половину преобразования (out в integral) на одной платформе и другую половину (in from integral) на другой платформе, вы рискуете, что system_clock::duration
будут иметь разные точности для двух преобразований.
Я бы также отметил, что есть два способа получить количество МС в точке времени. Я не уверен, какой из них лучше, я сравнил их, и они оба имеют одинаковую производительность, поэтому я думаю, что это вопрос предпочтения. Возможно, Говард мог бы вмешаться:--2-->
auto now = system_clock::now();
//Cast the time point to ms, then get its duration, then get the duration's count.
auto ms = time_point_cast<milliseconds>(now).time_since_epoch().count();
//Get the time point's duration, then cast to ms, then get its count.
auto ms = duration_cast<milliseconds>(tpBid.time_since_epoch()).count();
первый читается более ясно в моем уме, идя слева направо.
time_point
объекты только поддержка арифметики с другими time_point
или duration
объекты.
вам нужно будет преобразовать ваш long
до duration
указанных единиц, тогда ваш код должен работать правильно.