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
. І це наступне твердження стає по суті забороною (просто робить копію і не робить перетворення):
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
представлене з a long
і точністю seconds
. Це ефективно reinterpret_cast
вляет , milliseconds
котор тримають в value
до 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;
auto now = time_point_cast<milliseconds>(system_clock::now());
using sys_milliseconds = decltype(now);
auto integral_duration = now.time_since_epoch().count();
sys_milliseconds dt{milliseconds{integral_duration}};
if (dt != now)
std::cout << "Failure." << std::endl;
else
std::cout << "Success." << std::endl;
}
Основна небезпека, наведена вище, полягає в не тлумаченні integral_duration
як milliseconds
на шляху назад до a time_point
. Одним із можливих способів зменшити цей ризик є написання:
sys_milliseconds dt{sys_milliseconds::duration{integral_duration}};
Це зменшує ризик, просто переконуючись, що ви використовуєте sys_milliseconds
на виході та в двох місцях на зворотному шляху.
І ще один приклад: припустимо, ви хочете перетворити на інтеграл і з нього, який представляє будь-яку system_clock
підтримку тривалості (мікросекунди, 10 - та мікросекунда або наносекунда). Тоді вам не доведеться турбуватися про те, щоб вказати мілісекунди, як зазначено вище. Код спрощений до:
int main ()
{
using namespace std::chrono;
auto now = system_clock::now();
auto integral_duration = now.time_since_epoch().count();
system_clock::time_point dt{system_clock::duration{integral_duration}};
if (dt != now)
std::cout << "Failure." << std::endl;
else
std::cout << "Success." << std::endl;
}
Це працює, але якщо ви виконуєте половину перетворення (з цілого) на одній платформі, а другу половину (з цілого) на іншій платформі, ви ризикуєте system_clock::duration
мати різні точності для двох перетворень.
std::chrono::duration<long,std::milli> dur
і навіть тоді ви можете отримати помилки округлення (std::chrono::system_clock
мабуть, роздільна здатність вища, ніж мілісекунди).