コンテンツにスキップ

C++/標準ライブラリ/chrono

出典: フリー教科書『ウィキブックス(Wikibooks)』

C++標準ライブラリ <chrono> ヘッダー

[編集]

はじめに

[編集]

<chrono> ヘッダーの概要

[編集]

<chrono> ヘッダーは、C++ 標準ライブラリに時間操作用の機能を提供します。このヘッダーを使用すると、時間間隔 (Duration)、時点 (Time Point)、クロック (Clock) などの概念を扱うことができます。

従来の C++ では、時間操作は time_t 構造体や struct tm 構造体などを使用して行われていました。しかし、これらの構造体は精度が低く、操作が複雑でした。

<chrono> ヘッダーは、これらの問題を解決するために導入されました。このヘッダーを使用すると、高精度な時間操作を簡単に行うことができます。

時間の表現

[編集]

<chrono> ヘッダーでは、時間を以下の単位で表現することができます。

  • ナノ秒
  • マイクロ秒
  • ミリ秒
  • 時間

これらの単位は、std::chrono::nanosecondsstd::chrono::microsecondsstd::chrono::millisecondsstd::chrono::secondsstd::chrono::minutesstd::chrono::hoursstd::chrono::days などのクラスで定義されています。

<chrono> ヘッダーの利点

[編集]

<chrono> ヘッダーを使用すると、以下の利点があります。

  • 高精度な時間操作が可能
  • 操作が簡単
  • 移植性が高い
  • タイムゾーンに対応している

時間間隔 (Duration)

[編集]

duration クラス

[編集]

duration クラスは、2つの時間点間の時間間隔を表します。このクラスは、以下のメンバ関数を持っています。

get<T>()
時間間隔を指定された単位で取得します。
operator +operator -operator *operator /
時間間隔同士の演算を行います。
operator ==operator !=operator <operator <=operator >operator >=
時間間隔同士の比較を行います。

時間間隔の操作

[編集]

時間間隔は、以下の方法で操作することができます。

  • 時間間隔同士を加算したり、減算したりすることができます。
  • 時間間隔を定数倍したり、定数で割ることができます。
  • 時間間隔を比較することができます。

比較演算子

[編集]

時間間隔同士の比較には、以下の比較演算子を使用することができます。

operator ==
時間間隔が等しいかどうかを比較します。
operator !=
時間間隔が等しくないかどうかを比較します。
operator <
時間間隔が小さいかどうかを比較します。
operator <=
時間間隔が小さいか、または等しいかどうかを比較します。
operator >
時間間隔が大きいかどうかを比較します。
operator >=
時間間隔が大きいか、または等しいかどうかを比較します。

型変換

[編集]

時間間隔を他の単位に変換することができます。

std::chrono::seconds s = std::chrono::milliseconds(1000);

このコードは、1000 ミリ秒の時間間隔を秒に変換します。

リテラル

[編集]

時間間隔をリテラルで表現することができます。

std::chrono::seconds s = 10s;
std::chrono::milliseconds ms = 1000ms;

このコードは、10 秒の時間間隔と 1000 ミリ秒の時間間隔をリテラルで表現します。

特殊な時間間隔

[編集]

<chrono> ヘッダーには、以下の特殊な時間間隔が定義されています。

std::chrono::duration<int>
整数秒の時間間隔
std::chrono::duration<long long>
長整数秒の時間間隔
std::chrono::duration<float>
浮動小数点秒の時間間隔
std::chrono::duration<double>
倍精度浮動小数点秒の時間間隔

時点 (Time Point)

[編集]

time_point クラス

[編集]
operator +operator -
時点と時間間隔の演算を行います。
operator ==operator !=operator <operator <=operator >operator >=
時点同士の比較を行います。

時点の操作

[編集]

時点は以下の方法で操作することができます。

  • 時点に時間間隔を加算したり、減算したりすることができます。
  • 時点を比較することができます。

比較演算子

[編集]

時点同士の比較には、以下の比較演算子を使用することができます。

operator ==
時点が等しいかどうかを比較します。
operator !=
時点が等しくないかどうかを比較します。
operator <
時点が小さいかどうかを比較します。
operator <=
時点が小さいか、または等しいかどうかを比較します。
operator >
時点が大きいかどうかを比較します。
operator >=
時点が大きいか、または等しいかどうかを比較します。

型変換

[編集]

時点を他のクロックの時間点に変換することができます。

std::chrono::system_clock::time_point tp1 = std::chrono::steady_clock::now();
std::chrono::system_clock::time_point tp2 = tp1 + std::chrono::seconds(10);

このコードは、steady_clock の現在時刻 (tp1) に 10 秒の時間間隔を加算した system_clock の時間点 (tp2) を取得します。

特殊な時点

[編集]

<chrono> ヘッダーには、以下の特殊な時点が定義されています。

std::chrono::time_point<std::chrono::system_clock>
システムクロックの現在時刻
std::chrono::time_point<std::chrono::steady_clock>
高精度クロックの現在時刻
std::chrono::time_point<std::chrono::utc_clock>
協定世界時 (UTC) の現在時刻

クロック (Clock)

[編集]

クロックの種類

[編集]

<chrono> ヘッダーには、以下の種類のクロックが定義されています。

std::chrono::system_clock
システムクロック
std::chrono::steady_clock
高精度クロック
std::chrono::utc_clock
協定世界時 (UTC) クロック
std::chrono::tai_clock
国際原子時 (TAI) クロック
std::chrono::gps_clock
GPS クロック
std::chrono::file_clock
ファイルシステムクロック

これらのクロックは、それぞれ異なる特性を持っています。

system_clock
システムの標準的なクロックです。
steady_clock
高精度な時間測定が可能なクロックです。
utc_clock
協定世界時 (UTC) の時間を提供するクロックです。
tai_clock
国際原子時 (TAI) の時間を提供するクロックです。
gps_clock
GPS の時間を提供するクロックです。
file_clock
ファイルシステムの最終更新時刻に基づいて時間を提供するクロックです。

クロックの取得

[編集]

クロックは以下の方法で取得することができます。

std::chrono::system_clock sys_clock;
std::chrono::steady_clock stdy_clock;
std::chrono::utc_clock utc_clock;

このコードは、system_clocksteady_clockutc_clock のインスタンスを取得します。

時間測定

[編集]

クロックを使用して、時間間隔を測定することができます。

std::chrono::system_clock::time_point tp1 = sys_clock.now();
std::chrono::system_clock::time_point tp2 = sys_clock.now();
std::chrono::duration<double> d = tp2 - tp1;

このコードは、system_clock の現在時刻 (tp1) と (tp2) を取得し、2つの時間点間の時間間隔 (d) を測定します。

高精度クロック

[編集]

steady_clock は、system_clock よりも高精度な時間測定が可能です。これは、steady_clock がシステムクロックとは独立して動作するためです。

std::chrono::steady_clock::time_point tp1 = stdy_clock.now();
std::chrono::steady_clock::time_point tp2 = stdy_clock.now();
std::chrono::duration<double> d = tp2 - tp1;

このコードは、steady_clock の現在時刻 (tp1) と (tp2) を取得し、2つの時間点間の時間間隔 (d) を測定します。

タイムゾーン (Time Zone)

[編集]

タイムゾーンの概要

[編集]

タイムゾーンは、地球上の特定の地域における時刻を表すものです。タイムゾーンは、それぞれ異なるオフセット (UTC との差) を持っています。

<chrono> ヘッダーには、タイムゾーンを扱うための機能が提供されています。

タイムゾーン情報の取得

[編集]

タイムゾーン情報は、以下の方法で取得することができます。

std::chrono::system_clock::time_point tp = std::chrono::system_clock::now();
std::time_t t = std::chrono::system_clock::to_time_t(tp);
std::tm* tm = std::localtime(&t);
char str[100];
std::strftime(str, 100, "%Z", tm);
std::cout << str << std::endl; // JST

このコードは、現在のタイムゾーン (str) を取得します。

時点とタイムゾーンの変換

[編集]

時点とタイムゾーンを変換することができます。

std::chrono::system_clock::time_point tp = std::chrono::system_clock::now();
std::chrono::zoned_time<std::chrono::system_clock, std::chrono::Japan> zt = std::chrono::zoned_time(tp);
std::chrono::system_clock::time_point tp2 = zt.get_time();

このコードは、現在の時点 (tp) を日本標準時 (JST) に変換した時点 (tp2) を取得します。

夏時間

[編集]

<chrono> ヘッダーには、夏時間を処理するための機能が提供されています。

std::chrono::system_clock::time_point tp = std::chrono::system_clock::now();
std::chrono::zoned_time<std::chrono::system_clock, std::chrono::Europe/Berlin> zt = std::chrono::zoned_time(tp);
std::chrono::system_clock::time_point tp2 = zt.get_time();
std::cout << tp2 << std::endl; // 2024-05-30 21:05:30+02

このコードは、現在の時点 (tp) をベルリン標準時 (夏時間) (tp2) に変換します。

その他

[編集]

例外処理

[編集]

<chrono> ヘッダーの関数の中には、例外をスローするものがあります。

std::chrono::system_clock::time_point tp = std::chrono::time_point<std::chrono::system_clock>::from_time_t(0);

このコードは、time_t 型の値 (0) を system_clock::time_point 型に変換しようとします。しかし、0 は有効な時間ではないため、例外がスローされます。

スレッドセーフ性

[編集]

<chrono> ヘッダーのクラスと関数は、スレッドセーフではありません。

std::chrono::system_clock::time_point tp;
std::thread th1([&]() {
    tp = std::chrono::system_clock::now();
});
std::thread th2([&]() {
    tp = std::chrono::system_clock::now();
});
th1.join();
th2.join();

このコードは、2つのスレッド (th1th2) で system_clock::now() を呼び出し、その結果を tp に格納します。しかし、tp はスレッドセーフではないため、予期しない結果になる可能性があります。

関連ライブラリ

[編集]

<chrono> ヘッダーは、以下の関連ライブラリと連携することができます。

<ctime> ヘッダー
時間と日付の操作
<thread> ヘッダー
スレッド
<atomic> ヘッダー
原子操作
<locale> ヘッダー
ロケール
<ratio> ヘッダー
比率

附録

[編集]

<chrono> ヘッダーの主要な型と関数の概要

[編集]
ヘッダーの主要な型と関数
型/関数 説明
std::chrono::duration<T></syntaxhighlight> 時間間隔を表すクラス (T は時間単位)
std::chrono::time_point<T></syntaxhighlight> 時点を表すクラス (T はクロック)
std::chrono::system_clock</syntaxhighlight> システムクロック
std::chrono::steady_clock</syntaxhighlight> 高精度クロック
std::chrono::utc_clock</syntaxhighlight> 協定世界時 (UTC) クロック
std::chrono::zoned_time<T, TZ></syntaxhighlight> 特定のタイムゾーンにおける時点を表すクラス (T はクロック、TZ はタイムゾーン)
std::chrono::now()</syntaxhighlight> 現在の時点を取得する関数
std::chrono::from_time_t()</syntaxhighlight> time_t 型の値を time_point 型に変換する関数
std::chrono::to_time_t()</syntaxhighlight> time_point 型の値を time_t 型に変換する関数
std::chrono::get_time_since_epoch()</syntaxhighlight> エポックからの時間間隔を取得するメンバ関数
operator +, operator -</syntaxhighlight> 時間間隔同士の演算
operator ==, operator !=, operator <, operator <=, operator >, operator >=</syntaxhighlight> 時間間隔同士の比較
operator +, operator -</syntaxhighlight> 時点と時間間隔の演算
operator ==, operator !=, operator <, operator <=, operator >, operator >=</syntaxhighlight> 時点同士の比較
get_time_since_epoch()</syntaxhighlight> エポックからの時間間隔を取得するメンバ関数
std::strftime()</syntaxhighlight> 時点をフォーマットされた文字列に変換する関数
std::chrono::seconds::max()</syntaxhighlight> 最大の秒数
std::chrono::minutes::max()</syntaxhighlight> 最大の分数
std::chrono::hours::max()</syntaxhighlight> 最大の時間
std::chrono::days::max()</syntaxhighlight> 最大の日数

C++11 と C++20 の変更点

[編集]

C++20 では、<chrono> ヘッダーに以下の変更が加えられました。

  • 新しいカレンダーとタイムゾーン関連の機能が追加されました。
  • std::chrono::is_clock メタ関数が追加されました。
  • 一部の関数の名前が変更されました。

まとめ

[編集]

<chrono> ヘッダーは、C++ 標準ライブラリに時間操作用の機能を提供します。このヘッダーを使用すると、高精度な時間操作を簡単に行うことができます。

<chrono> ヘッダーは、以下の用途に役立ちます。

  • パフォーマンスの測定
  • タイムアウトの実装
  • アニメーションの作成
  • ネットワークアプリケーションの開発

このヘッダーは、C++ プログラマーにとって必須のツールです。