メインコンテンツへスキップ

C++20 std::chrono::sys_clock, std::chrono::utc_clockのtime_pointを整数型で保持する

··1174 文字·3 分·
プログラミング C++ C++20
著者
Admin
目次

std::chrono, std::chrono::xxx_clock, time_pointとは
#

この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);
  };

Related

C++23 std::expected<void, T>でreturnを書かないとsigillが出る罠
··963 文字·2 分
プログラミング C++ C++23
Getter、Setterとは? 必要かどうか迷った場合に考えること
··1588 文字·4 分
プログラミング Rust C++
構造体やクラスのフィールドのpublicやprivateについても解説しています。
DolphinエミュレーターでスマブラXをプレイする際に曲を別に流せるようにする
··2566 文字·6 分
プログラミング スマブラX dolphin C++ toml miniaudio xtool