時間を無次元の量として扱うと、測定単位の変換で誤解やエラーが発生する可能性があります。
-聞いて、覚えてないよ、私たちは睡眠中に秒またはミリ秒を送信しますか?
-くそー、それは私が私の時間に360秒を持っていることが判明した、私はゼロを逃した。
このようなエラーを回避するために、クロノライブラリ(名前空間std :: chrono)が提供されています。 C ++ 11で追加され、後の標準で最終決定されました。 今ではすべてが論理的です:
using namespace std::chrono; int find_answer_to_the_ultimate_question_of_life() { // std::this_thread::sleep_for(5s); //5 return 42; } std::future<int> f = std::async(find_answer_to_the_ultimate_question_of_life); // 2.5 if (f.wait_for(2500ms) == std::future_status::ready) std::cout << "Answer is: " << f.get() << "\n"; else std::cout << "Can't wait anymore\n";
ライブラリには、次の概念が実装されています。
- 時間間隔-
duration
; - 時点
time_point
; - タイマー-
clock
。
std ::比率
std :: ratio-コンパイル時の通常分数(m / n)を実装するテンプレートクラス。 これはchronoに属していませんが、このライブラリで積極的に使用されているため、最初にそれを知って、それ以上の質問を引き起こさないようにします。
template< std::intmax_t Num, // std::intmax_t Denom = 1 // > class ratio;
分子と分母がテンプレートconstexprパラメーターであることが重要です。 これにより、コンパイル段階で型を形成できます。 このクラスは補助(純粋に静的なヘルパークラス)であり、一般的には数学的な計算を目的とするものではありません。 ユニットを効果的に翻訳するために必要です。 たとえば、距離の異なる単位を使用したい場合:
template<class _Ratio> class Length { double length_; public: explicit Length(double length) : length_(length) { } double length() const { return length_; } }; Length<Mm> len1(127.0); Length<Inches> len2(5.0); Length<Mm> len3 = len1 + len2;
ミリメートルを基本単位とすると、次のようになります。
using Mm = std::ratio<1>; // == 1 // , : using Inches = std::ratio<254, 10>; using Metre = std::ratio<1000, 1>;
コンストラクターでは、ベースユニットへの変換を実行できました。 ただし、この変換が必要な場合にのみより正確です。 メートルからミリメートルへの変換は、丸め中の損失を恐れることなく変換できるためです。
上記に関連して、完全を期すために、加算操作の最も成功した実装ではなく、単純な実装を示します。
template<class _Ratio1, class _Ratio2> Length<Mm> operator+(const Length<_Ratio1> &left, const Length<_Ratio2> &right) { double len = left.length() / _Ratio1::den * _Ratio1::num + right.length() / _Ratio2::den * _Ratio2::num; return Length<Mm>((int)len); }
メートルとキロメートルを追加するときにメートルを取得するのが正しいでしょう。
期間-時間間隔
テンプレートクラスstd :: chrono :: durationは、時間間隔タイプです。 クロノの時間間隔は、一定の期間数です(元のティック期間内)。 この数値は、 int64_t
やfloat
などのタイプによって特徴付けられます。 期間の長さは秒単位で測定され、std :: ratioを使用して自然な分数として表されます。
いくつかの一般的な間隔は既にライブラリで定義されています。 タイプは実装によって若干異なる場合があります。
using nanoseconds = duration<long long, nano>; using microseconds = duration<long long, micro>; using milliseconds = duration<long long, milli>; using seconds = duration<long long>; using minutes = duration<int, ratio<60> >; using hours = duration<int, ratio<3600> >; // nano, micro, milli: using nano = ratio<1, 1000000000>; using micro = ratio<1, 1000000>; using milli = ratio<1, 1000>;
ただし、独自に定義できます。
using namespace std::chrono; //3- using Hourglass = duration<long, std::ratio<180>>; // using Hourglass = duration<long, std::ratio_multiply<std::ratio<3>, minutes::period>>; // 2.75 using MyTimeUnit = duration<long, std::ratio<11, 4>>; // . using fseconds = duration<float>; // - using seconds16 = duration<uint16_t>;
次に、それらの使用方法。 暗黙的な初期化は禁止されています:
seconds s = 5; // void foo(minutes); foo(42); //
明示的のみ:
seconds s{8}; void foo(minutes); foo(minutes{42});
ところで、ブレースが使用される理由については、たとえばここを読むことができます 。 要するに:不可逆積分型の暗黙的な変換を避けるため。 T x(F());
別のケースを追加しT x(F());
xを初期化する代わりに、タイプF(*)()
関数へのポインターを取り、 T
を返す関数を宣言するものとして解釈されますT
解決策: T x{F()};
またはT x((F()));
。
C ++ 14は、基本単位のカスタムリテラルを追加します。
seconds s = 4min; void foo(minutes); foo(42min);
以下を追加、減算、比較できます。
seconds time1 = 5min + 17s; minutes time2 = 2h - 15min; bool less = 59s < 1min;
上記の例のように、時間を分から秒、分から秒、秒からミリ秒などに暗黙的に変換できますが、その逆はできません。
minutes time3 = 20s; // seconds time4 = 2s + 500ms; //
一般に、周期比が整数の場合、整数型の暗黙的な変換が許可されます。
//(20/15) / (1/3) = 4. ! duration<long, std::ratio<1, 3>> t1 = duration<long, std::ratio<20, 15>>{ 1 };
それ以外の場合、丸めと浮動小数点型への変換の2つの方法があります。
// - minutes m1 = duration_cast<minutes>(-100s); //-1m //C++17. minutes m2 = round<minutes>(-100s); //-2m //C++17. minutes m3 = ceil<minutes>(-100s); //-1m //C++17. minutes m4 = floor<minutes>(-100s); //-2m
2番目のオプション:
using fminutes = duration<float, minutes::period>; fminutes m = -100s;
タイプuint64_tの秒数の冗長表現があるとします。 OK:
using seconds16 = duration<uint16_t, seconds::period>; seconds16 s = 15s;
しかし、あなたはまだオーバーフローを恐れています。 ライブラリのクラスを使用して、安全に数字を操作できます。 標準にはそのような標準はありませんが(提案のみ)、サードパーティの実装があります。 VSにもあります、私たちはそれを使用します:
#include <safeint.h> using sint = msl::utilities::SafeInt<uint16_t>; using safe_seconds16 = duration<sint, seconds::period>; safe_seconds16 ss = 60000s; try { ss += 10000s; } catch (msl::utilities::SafeIntException e) { // };
画面またはファイルに間隔値を表示するには、count()を使用する必要があります。
seconds s = 15s; std::cout << s.count() << "s\n";
ただし、内部変換にはcountを使用しないでください!
time_point-時点
time_pointクラスは、時刻を表すことを目的としています。 時間の瞬間は、特定の基準点から開始する任意のタイマーで測定される時間間隔として特徴付けることができます。 たとえば、ストップウォッチを使用してスープを調理している場合、時刻は次のように表すことができます。
0 : 420 : 1300 :
壁掛け時計の分針の場合、同じ時点は次のようになります。
17 : 24 : 39 :
クラス自体:
template< class Clock, class Duration = typename Clock::duration > class time_point;
時間間隔のタイプはすでによく知られているので、クロックタイマーに移りましょう。 ライブラリには3つのタイマーがあります。
- system_clock-システム時間を表します。 通常、このタイマーは、測定中にユーザーまたは同期プロセスによって時間を変更できるため、間隔の測定には適していません。 通常、1970年1月1日からの経過時間に基づいていますが、これは指定されていません。
- steady_clock-いわゆる安定したクロックを表します。つまり、そのコースは外部の変更の影響を受けません。 間隔の測定に適しています。 通常、その実装は、スイッチオン後のシステムの稼働時間に基づいています。
- high_resolution_clock-システムで使用可能な最小のサンプル期間を持つタイマー。 考えられているものの1つのエイリアスである可能性があります(ほぼ間違いなく、steady_clockです)。
クロックには静的変数is_steady
あり、これによりタイマーが単調かどうかを確認できます。 Clockには現在関数があり、time_pointの形式で現在の時刻を返します。 time_point
クラスのオブジェクトtime_point
あまり興味深いものではありません。その起源の瞬間は特定ではなく、ほとんど意味をなさないからです。 ただし、時間間隔を追加して、他の時点と比較することができます。
time_point<steady_clock> start = steady_clock::now(); // steady_clock::time_point start = steady_clock::now(); // auto start = steady_clock::now(); foo(); if (steady_clock::now() < start + 1s) std::cout << "Less than a second!\n";
time_point
をtime_point
に追加することはできませんが、減算することはできます。これは時間の追跡に役立ちます。
auto start = steady_clock::now(); foo(); auto end = steady_clock::now(); auto elapsed = duration_cast<milliseconds>(end - start);
カウントダウンの開始からの時間間隔を取得するには、 time_since_epoch
を呼び出しtime_since_epoch
。
auto now = system_clock::now(); system_clock::duration tse = now.time_since_epoch();
time_point
を数値に変換する(たとえば、シリアル化または表示用)には、Cタイプのtime_tを使用します。
auto now = system_clock::now(); time_t now_t = system_clock::to_time_t(now); auto now2 = system_clock::from_time_t(now_t);
結論の代わりに
最も一般的な質問:時間と日付を読みやすい形式で表示する方法。 クロノでは、何もありません。 time_tで遊ぶか、クロノ開発者の別のライブラリを使用できます。