std::chrono, std::chrono::xxx_clock, time_pointとは #
- std::chrono: 🔗https://en.cppreference.com/w/cpp/header/chrono
日本語: 🔗https://cpprefjp.github.io/reference/chrono.html - std::chrono::utc_clock: 🔗https://en.cppreference.com/w/cpp/chrono/utc_clock
日本語: 🔗https://cpprefjp.github.io/reference/chrono/utc_clock.html - std::chrono::system_clock: 🔗https://en.cppreference.com/w/cpp/chrono/system_clock
日本語: 🔗https://cpprefjp.github.io/reference/chrono/system_clock.html - std::chrono::time_point: 🔗https://en.cppreference.com/w/cpp/chrono/time_point
日本語: 🔗https://cpprefjp.github.io/reference/chrono/time_point.html
このtime_pointを整数型でコンパクトに保持したい。
sizeof(utc_clock::time_point)
は8バイトだったのでそのままでも十分コンパクトなのだが、シリアライズする必要があり、ライブラリが対応していないので整数型にしようというわけだ。
time_pointと整数型間の変換 #
精度はstd::chrono::nanoseconds
で実装しています。
コード #
ヘッダーファイルutility/chrono.hpp
#pragma once
#include <chrono>
std::uint64_t
utc_clock_timepoint_to_u64(std::chrono::utc_clock::time_point const &tp);
std::chrono::utc_clock::time_point
u64_to_utc_clock_timepoint(std::uint64_t const time_since_epoch_nanoseconds);
ソースファイルutility/chrono.cpp
#include <chrono>
#include <utility/chrono.hpp>
std::uint64_t
utc_clock_timepoint_to_u64(std::chrono::utc_clock::time_point const &tp) {
auto const nanosec_tp =
std::chrono::time_point_cast<std::chrono::nanoseconds>(tp);
auto const epoch_duration = nanosec_tp.time_since_epoch();
return epoch_duration.count();
}
std::chrono::utc_clock::time_point
u64_to_utc_clock_timepoint(std::uint64_t const time_since_epoch_nanoseconds) {
std::chrono::nanoseconds duration(time_since_epoch_nanoseconds);
std::chrono::time_point<std::chrono::utc_clock, std::chrono::nanoseconds> tp(
duration);
return tp;
}
検証 #
数ケースでテストを行った。
#include <chrono>
#include <gtest/gtest.h>
#include <test.hpp>
#include <utility/chrono.hpp>
TEST(UtilityChrono, StdChronoUtcClockTimePointConversion) {
using namespace std::chrono_literals;
auto const sys_to_utc_fn =
[](std::chrono::system_clock::time_point const &sys_tp)
-> std::chrono::utc_clock::time_point {
// utc clock tp
return std::chrono::clock_cast<std::chrono::utc_clock>(sys_tp);
};
std::vector<std::chrono::utc_clock::time_point> time_points_to_test;
time_points_to_test.push_back(std::chrono::utc_clock::now());
// sys clock tp
std::chrono::time_point<std::chrono::system_clock> sys_tp1 =
std::chrono::sys_days{1999y / 12 / 31} + 23h + 45min;
time_points_to_test.push_back(sys_to_utc_fn(sys_tp1));
time_points_to_test.push_back(
sys_to_utc_fn(std::chrono::sys_days{1999y / 12 / 31} + 23h + 45min));
time_points_to_test.push_back(
sys_to_utc_fn(std::chrono::sys_days{7777y / 7 / 17} + 17h + 77min));
time_points_to_test.push_back(
sys_to_utc_fn(std::chrono::sys_days{2025y / 4 / 17} + 0h + 7min));
time_points_to_test.push_back(
sys_to_utc_fn(std::chrono::sys_days{0y/ 0 / 0} + 0h + 0min));
for (auto const &utc_tp : time_points_to_test) {
// time_point を std::uint64_t に変換
auto const u64 =
utc_clock_timepoint_to_u64(utc_tp);
// std::uint64_t を time_point に変換
auto const decoded_tp =
u64_to_utc_clock_timepoint(u64);
// 一致することを確認
ASSERT_EQ(utc_tp, decoded_tp);
}
}
結果
6/6 test-utility-chrono OK 0.01s
(6ケース全パス)
まとめ #
std::chrono::utc_clock, std::chrono::sys_clockのtimepoint(std::chrono::utc_clock::time_point
,std::chrono::system_clock::time_point
)は整数型に/から変換することができるので、8バイトでタイムスタンプを保持できる!
time_point間の変換はC++20のclock_cast
で可能。
🔗https://en.cppreference.com/w/cpp/chrono/clock_cast
auto const sys_to_utc_fn =
[](std::chrono::system_clock::time_point const &sys_tp)
-> std::chrono::utc_clock::time_point {
return std::chrono::clock_cast<std::chrono::utc_clock>(sys_tp);
};