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мабуть, роздільна здатність вища, ніж мілісекунди).