1. ホーム
  2. c++

[解決済み] C++ std::chrono::time_point を long に変換して戻すには?

2022-11-29 01:07:37

質問

を変換する必要があります。 std::chrono::time_point から long 型(64ビット整数)に変換します。私は std::chrono ...

以下は私のコードです。

int main ()
{
     std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();

    auto epoch = now.time_since_epoch();
    auto value = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);
    long duration = value.count();


    std::chrono::duration<long> dur(duration);

    std::chrono::time_point<std::chrono::system_clock> dt(dur);

    if (dt != now)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}

このコードはコンパイルされますが、成功を示しません。

なぜ dt とは異なり now とは違うのですか?

そのコードには何が欠けているのでしょうか?

どのように解決するのですか?

std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();

これは auto :

auto now = std::chrono::system_clock::now();

でトラフィックしたいので millisecond の精度でトラフィックしたいので、先に進んで time_point :

auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);

now_mstime_point に基づいています。 system_clock の精度で、しかし milliseconds の精度ではなく system_clock が持つ精度ではなく

auto epoch = now_ms.time_since_epoch();

epoch は、現在、タイプ std::chrono::milliseconds . そして、この次の文は本質的にno-opになります(単にコピーを作成し、変換を行いません)。

auto value = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);

ここで

long duration = value.count();

あなたのコードでも私のコードでも duration の数を保持します。 milliseconds のエポックから system_clock .

これ

std::chrono::duration<long> dur(duration);

を作成します。 duration で表される long であり、精度は seconds . これは事実上 reinterpret_castmilliseconds で開催された valueseconds . これはロジックエラーです。 正しいコードは次のようになります。

std::chrono::milliseconds dur(duration);

この行は

std::chrono::time_point<std::chrono::system_clock> dt(dur);

time_point に基づいて system_clock に精度を保持する機能を持つ。 system_clock のネイティブ精度(通常はミリ秒より細かい)を保持する機能を持つ。 しかし、実行時の値は、ミリ秒の整数値が保持されていることを正しく反映します。 dur ).

修正しても、このテストは(ほぼ)失敗しますが。

if (dt != now)

なぜなら dt には整数個の milliseconds を保持するが now よりも細かい刻みの整数倍を保持します。 millisecond (よりも細かい刻みを保持します(例えば microseconds または nanoseconds ). したがって、ごくまれに system_clock::now() が整数を返した場合のみ milliseconds が返ってくれば、テストは合格です。

しかし、代わりに

if (dt != now_ms)

そして、これで期待通りの結果を確実に得ることができます。

すべてをまとめると

int main ()
{
    auto now = std::chrono::system_clock::now();
    auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);

    auto value = now_ms.time_since_epoch();
    long duration = value.count();

    std::chrono::milliseconds dur(duration);

    std::chrono::time_point<std::chrono::system_clock> dt(dur);

    if (dt != now_ms)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}

個人的には、すべての std::chrono は冗長すぎると思うので、私ならこうコーディングします。

int main ()
{
    using namespace std::chrono;
    auto now = system_clock::now();
    auto now_ms = time_point_cast<milliseconds>(now);

    auto value = now_ms.time_since_epoch();
    long duration = value.count();

    milliseconds dur(duration);

    time_point<system_clock> dt(dur);

    if (dt != now_ms)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}

どちらが確実に出力されるかというと

Success.

最後に、テンポラリを排除して time_point と積分型の間で変換するコードを最小にするために、テンポラリをなくすことをお勧めします。 これらの変換は危険なので、素の積分型を操作するコードを書くのは少なければ少ないほどよいのです。

int main ()
{
    using namespace std::chrono;
    // Get current time with precision of milliseconds
    auto now = time_point_cast<milliseconds>(system_clock::now());
    // sys_milliseconds is type time_point<system_clock, milliseconds>
    using sys_milliseconds = decltype(now);
    // Convert time_point to signed integral type
    auto integral_duration = now.time_since_epoch().count();
    // Convert signed integral type to time_point
    sys_milliseconds dt{milliseconds{integral_duration}};
    // test
    if (dt != now)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}

上記の主な危険は ではなく を解釈することです。 integral_duration として milliseconds に戻る途中 time_point . そのリスクを軽減する方法として考えられるのは、「書く」ことです。

    sys_milliseconds dt{sys_milliseconds::duration{integral_duration}};

これにより、リスクを減らすことができます。 sys_milliseconds を使うようにするだけです。

もう一つ例を挙げましょう。 例えば、次のような持続時間を表す積分に変換したいとします。 system_clock がサポートする時間 (マイクロ秒、10 th というように、マイクロ秒やナノ秒を指定することができます。) そうすれば、上記のようなミリ秒の指定に悩まされることはない。 コードは次のように単純化されます。

int main ()
{
    using namespace std::chrono;
    // Get current time with native precision
    auto now = system_clock::now();
    // Convert time_point to signed integral type
    auto integral_duration = now.time_since_epoch().count();
    // Convert signed integral type to time_point
    system_clock::time_point dt{system_clock::duration{integral_duration}};
    // test
    if (dt != now)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}

これはうまくいきますが、もし半分の変換(out to integral)をあるプラットフォームで、残りの半分(in from integral)を別のプラットフォームで実行した場合、以下のようなリスクがあります。 system_clock::duration は 2 つの変換で異なる精度を持つというリスクを伴います。