web-dev-qa-db-ja.com

C ++のstd :: chrono :: time_pointから年/月/日などを抽出する

std::chrono::time_pointオブジェクトから年、月、日、時間、分、秒、ミリ秒を抽出するにはどうすればよいですか?

私は例の合計量を抽出する方法の例を見ました。 durationからの秒数。

42
bytecode77

この情報はsystem_clock::time_pointからのみ抽出できます。これは、市民カレンダーと関係がある唯一のシステム提供の時計です。このクロックを使用して現在のtime_pointを取得する方法は次のとおりです。

 system_clock::time_point now = system_clock::now();

次に、これをtime_tに変換します:

time_t tt = system_clock::to_time_t(now);

Cライブラリを使用すると、time_ttmに変換できますが、UTCタイムゾーンで変換するか、ローカルタイムゾーンで変換するかを選択する必要があります。

tm utc_tm = *gmtime(&tt);
tm local_tm = *localtime(&tt);

次に、tmのコンポーネントを印刷できます。次に例を示します。

std::cout << local_tm.tm_year + 1900 << '\n';
std::cout << local_tm.tm_mon + 1 << '\n';
std::cout << local_tm.tm_mday << '\n';

さらに

必要に応じて、次の非保証情報を利用できます。

私が知っているsystem_clockのすべての実装は、 nix time に基づいています。つまりうるう秒を無視して、1970年の新年UTCからの秒数。そして、このカウントの精度は通常、秒よりも細かいです。この情報をすべて抽出する完全なプログラムを次に示します。

#include <chrono>
#include <ctime>
#include <iostream>

int
main()
{
    using namespace std;
    using namespace std::chrono;
    typedef duration<int, ratio_multiply<hours::period, ratio<24> >::type> days;
    system_clock::time_point now = system_clock::now();
    system_clock::duration tp = now.time_since_Epoch();
    days d = duration_cast<days>(tp);
    tp -= d;
    hours h = duration_cast<hours>(tp);
    tp -= h;
    minutes m = duration_cast<minutes>(tp);
    tp -= m;
    seconds s = duration_cast<seconds>(tp);
    tp -= s;
    std::cout << d.count() << "d " << h.count() << ':'
              << m.count() << ':' << s.count();
    std::cout << " " << tp.count() << "["
              << system_clock::duration::period::num << '/'
              << system_clock::duration::period::den << "]\n";

    time_t tt = system_clock::to_time_t(now);
    tm utc_tm = *gmtime(&tt);
    tm local_tm = *localtime(&tt);
    std::cout << utc_tm.tm_year + 1900 << '-';
    std::cout << utc_tm.tm_mon + 1 << '-';
    std::cout << utc_tm.tm_mday << ' ';
    std::cout << utc_tm.tm_hour << ':';
    std::cout << utc_tm.tm_min << ':';
    std::cout << utc_tm.tm_sec << '\n';
}

カスタムのdurationを作成して日をモデル化すると便利です。

typedef duration<int, ratio_multiply<hours::period, ratio<24> >::type> days;

これで、エポック以降の時間を、管理できる限りの精度で取得できます。

system_clock::duration tp = now.time_since_Epoch();

次に、それを数日に切り捨てて、それを差し引きます。

次に、それを数時間に切り捨て、それを差し引きます。

秒を差し引くまで続けます。

残っているのは、system_clock::durationの単位の1秒未満です。したがって、示されているように、その実行時の値とその値のコンパイル時間の単位を印刷します。

私にとって、このプログラムは次のように出力します。

15806d 20:31:14 598155[1/1000000]
2013-4-11 20:31:14

私の出力は、system_clock::duration精度がマイクロ秒であることを示しています。必要に応じて、次のようにしてミリ秒に切り捨てることができます。

milliseconds ms = duration_cast<milliseconds>(tp);

更新

このヘッダーのみのC++ 11/14ライブラリ は上記の作業をカプセル化し、クライアントの作業を次のように削減します。

#include "date.h"
#include <iostream>

int
main()
{
    // Reduce verbosity but let you know what is in what namespace
    namespace C = std::chrono;
    namespace D = date;
    namespace S = std;

    auto tp = C::system_clock::now(); // tp is a C::system_clock::time_point
    {
        // Need to reach into namespace date for this streaming operator
        using namespace date;
        S::cout << tp << '\n';
    }
    auto dp = D::floor<D::days>(tp);  // dp is a sys_days, which is a
                                      // type alias for a C::time_point
    auto ymd = D::year_month_day{dp};
    auto time = D::make_time(C::duration_cast<C::milliseconds>(tp-dp));
    S::cout << "year        = " << ymd.year() << '\n';
    S::cout << "month       = " << ymd.month() << '\n';
    S::cout << "day         = " << ymd.day() << '\n';
    S::cout << "hour        = " << time.hours().count() << "h\n";
    S::cout << "minute      = " << time.minutes().count() << "min\n";
    S::cout << "second      = " << time.seconds().count() << "s\n";
    S::cout << "millisecond = " << time.subseconds().count() << "ms\n";
}

私のためにちょうど出力:

2015-07-10 20:10:36.023017
year        = 2015
month       = Jul
day         = 10
hour        = 20h
minute      = 10min
second      = 36s
millisecond = 23ms

別の更新

このライブラリはC++標準の提案に成長し、現在C++ 20のワーキングドラフトに含まれています。 C++ 20のsystem_clock::time_pointからこれらのフィールドを抽出するための構文は次のとおりです。

#include <chrono>

int
main()
{
    using namespace std::chrono;
    auto tp = system_clock::now();
    auto dp = floor<days>(tp);
    year_month_day ymd{dp};
    hh_mm_ss time{floor<milliseconds>(tp-dp)};
    auto y = ymd.year();
    auto m = ymd.month();
    auto d = ymd.day();
    auto h = time.hours();
    auto M = time.minutes();
    auto s = time.seconds();
    auto ms = time.subseconds();
}

上記では、UTCでこれらのフィールドが必要であることを前提としています。他のタイムゾーンでそれらを好む場合、それも可能です。たとえば、コンピューターの現在のローカルタイムゾーンでこれを行う方法は次のとおりです。

#include <chrono>

int
main()
{
    using namespace std::chrono;
    auto tp = zoned_time{current_zone(), system_clock::now()}.get_local_time();
    auto dp = floor<days>(tp);
    year_month_day ymd{dp};
    hh_mm_ss time{floor<milliseconds>(tp-dp)};
    auto y = ymd.year();
    auto m = ymd.month();
    auto d = ymd.day();
    auto h = time.hours();
    auto M = time.minutes();
    auto s = time.seconds();
    auto ms = time.subseconds();
}

上記の唯一の違いは、UTCの例のlocal_timeではなくsys_time型を持つtpの構築です。あるいは、この小さな変更で任意のタイムゾーンを選択することもできます。

auto tp = zoned_time{"Europe/London", system_clock::now()}.get_local_time();
64
Howard Hinnant