はじめに
C++で日付や時間を扱う際、従来はC言語由来のtime.h
を使うなど、少し扱いが面倒でした。C++20では、**<chrono>
**ライブラリが大幅に拡張され、タイムゾーンの扱いや日付・時刻のフォーマットが、非常に簡単かつ型安全に行えるようになりました。
この記事では、C++20の<chrono>
ライブラリの主要な機能を、以下のカテゴリに分けて網羅的に解説します。
- 現在時刻の取得とフォーマット
- 経過時間 (
duration
) の扱い - 指定時間まで待機
【前提】C++20とは?
C++20は、2020年に正式化されたC++言語のメジャーアップデート版です。この記事で紹介する機能の多くはC++20で導入されたため、利用するにはC++20に対応したコンパイラが必要です。
1. 現在時刻の取得とフォーマット
std::chrono::system_clock::now()
で現在のシステム時刻を取得し、std::format
(C++20) や zoned_time
を使って、特定のタイムゾーンの日付や時刻として整形できます。
サンプルコード
#include <iostream>
#include <chrono>
#include <format> // std::format (C++20)
using namespace std;
using namespace std::chrono;
int main() {
// 1. 現在のシステム時刻を取得
system_clock::time_point now = system_clock::now();
// 2. タイムゾーンを指定して表示 (日本時間)
cout << "現在時刻 (日本): " << zoned_time{"Asia/Tokyo", now} << endl;
// 3. タイムゾーンを指定して表示 (協定世界時)
cout << "現在時刻 (UTC): " << zoned_time{"UTC", now} << endl;
// 4. std::formatで、好きな書式に整形
cout << "フォーマット (Y-m-d H:M:S): "
<< format("{:%Y-%m-%d %H:%M:%S}", zoned_time{"Asia/Tokyo", now}) << endl;
// 5. 日付だけ、時間だけを取り出す
auto zt = zoned_time{"Asia/Tokyo", now};
// floor<days>で日付部分に丸める
year_month_day ymd{floor<days>(zt.get_local_time())};
// 時:分:秒の部分を取得
hh_mm_ss hms{zt.get_local_time() - floor<days>(zt.get_local_time())};
cout << "日付のみ: " << ymd << endl;
cout << "時間のみ: " << hms << endl;
return 0;
}
2. 経過時間 (duration
) の扱い
duration
は、時間の「長さ」を表現するクラスです。seconds
, milliseconds
などが用意されており、単位の変換や計算を型安全に行えます。
サンプルコード
#include <iostream>
#include <chrono>
using namespace std;
using namespace std::chrono;
using namespace std::chrono_literals; // "s", "ms" などのリテラルを使うために必要
int main() {
// 1. 単位の変換
milliseconds ms1 = seconds{5}; // 5秒は5000ミリ秒
cout << "5秒 = " << ms1.count() << "ミリ秒" << endl;
seconds s = duration_cast<seconds>(milliseconds{3800}); // 3800ミリ秒 -> 3秒 (切り捨て)
cout << "3800ミリ秒を秒に変換 (切り捨て): " << s.count() << "秒" << endl;
// 2. 異なる単位同士の演算
milliseconds total_ms = seconds{2} + milliseconds{500};
cout << "2秒 + 500ミリ秒 = " << total_ms.count() << "ミリ秒" << endl;
// 3. durationリテラル (C++14)
auto total_duration = 1min + 30s + 100ms;
cout << "1分30秒100ミリ秒 = "
<< duration_cast<milliseconds>(total_duration).count() << "ミリ秒" << endl;
return 0;
}
解説:
duration_cast
:milliseconds
をseconds
に変換するなど、精度の粗い単位へ安全に変換(キャスト)するために使います。- リテラル:
1min
や30s
のように、数値の後ろに単位を付けるだけで、直感的にduration
オブジェクトを生成できます。
3. 指定時間まで待機する
他のスレッドの処理を待ったり、一定間隔で処理を実行したりするために、指定した時間だけ現在のスレッドをスリープさせることができます。 (この機能は <thread>
ヘッダーで提供されます)
サンプルコード
#include <iostream>
#include <chrono>
#include <thread> // this_thread::sleep_for
using namespace std;
using namespace std::chrono;
int main() {
cout << "処理を開始します。" << endl;
// 現在の時刻から5秒後の時刻を計算
auto end_time = system_clock::now() + seconds{5};
// 5秒間スリープする (より現代的な書き方)
// this_thread::sleep_for(seconds{5});
// 指定時刻になるまでビジーウェイトで待機する
while (system_clock::now() < end_time) {
// ループで待機
}
cout << "5秒経過したので、処理を終了します。" << endl;
return 0;
}
解説: ご提示の while
ループによる待機(ビジーウェイト)はCPUを消費するため、std::this_thread::sleep_for()
や sleep_until()
を使うのが一般的で、より効率的です。
まとめ
今回は、C++20の<chrono>
ライブラリを使った、現代的な時間操作の基本を解説しました。duration
やtime_point
といった型システムにより、単位の間違いなどをコンパイル時に防ぎつつ、タイムゾーンや書式設定といった複雑な処理を、驚くほど簡単かつ安全に記述できるようになっています。