C++20 のカレンダーとタイム ゾーン:タイム ゾーン

この投稿で、C++20 の chrono 拡張機能の紹介を終わります。今日はタイムゾーン機能を紹介します。

書くべきだったのですが、今日は主に C++20 のタイムゾーン機能を紹介します。 C++20 のタイム ゾーンについて書く前に、新しいクロノ機能の例が約 40 ある Howard Hinnant のオンライン リソースの例とレシピを紹介したいと思います。おそらく、C++20 の chrono 拡張機能は簡単には入手できません。したがって、非常に多くの例を持つことが非常に重要です。これらの例をさらなる実験の出発点として使用し、理解を深めてください。レシピを追加することもできます。

例とレシピのアイデアを得るために、序数の日付を計算する Roland Bock のプログラムを提示したいと思います.

序数の日付の計算

"序数の日付は、年と 1 日 (1 月 1 日は 1 日、12 月 31 日は 365 日または 366 日) で構成されます。年は year_month_day から直接取得できます。以下のコードでは、year_month_day が 1 月 0 日などの無効な日付を処理できることを示しています :" (ローランド・ボック)

Roland のプログラムに必要なヘッダーを追加しました。

// ordinalDate.cpp

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

int main()
{
 using namespace date;
 
 const auto time = std::chrono::system_clock::now();
 const auto daypoint = floor<days>(time); // (1) 
 const auto ymd = year_month_day{daypoint}; 
 
 // calculating the year and the day of the year
 const auto year = ymd.year();
 const auto year_day = daypoint - sys_days{year/January/0}; // (2) 
 // (3)
 std::cout << year << '-' << std::setfill('0') << std::setw(3) << year_day.count() << std::endl;
 
 // inverse calculation and check
 assert(ymd == year_month_day{sys_days{year/January/0} + year_day});
}

プログラムにいくつかのコメントを追加したいと思います。行 (1) は、現在の時点を切り捨てます。この値は、カレンダーの日付を初期化するために次の行で使用されます。行 (2) は、2 つの時点の間の期間を計算します。どちらの時点にも解決日があります。最後に year_day.count() inline (3) は期間を日数で返します。

タイムゾーンに関する次の例は、前述の Web リソースの例とレシピにも触発されています。

タイムゾーン

まず、タイムゾーンは地域であり、夏時間やうるう秒などの日付の完全な履歴です。 C++20 のタイム ゾーン ライブラリは、IANA タイム ゾーン データベースの完全なパーサーです。次の表は、新しい機能の最初のアイデアを提供するはずです。

私の例では、関数 std::chrono::zones_time を使用しています これは基本的に、タイム ゾーンと時刻を組み合わせたものです。

2 つの例を紹介する前に、簡単に説明したいと思います。タイムゾーン ライブラリを使用してプログラムをコンパイルするには、 tz.cpp をコンパイルする必要があります。 ファイルを作成し、curl に対してリンクします。 図書館。現在の IANA タイムゾーン データベースを取得するには、curl ライブラリが必要です。次の g++ のコマンド ラインから、アイデアが得られるはずです:

g++ localTime.cpp -I <Path to data/tz.h> tz.cpp -std=c++17 -lcurl -o localTime

私の最初のプログラムは簡単です。 UTC 時間と現地時間を表示します。

UTC 時間と現地時間

UTC 時間または協定世界時は、世界の主要な時間標準です。コンピュータは、UTC に非常に近い Unix 時間を使用します。 UNIX 時間は、Unix エポックからの秒数です。 Unix エポックは 1970 年 1 月 1 日の 00:00:00 UTC です。

std::chrono::system_clock::now() inline (1) は、次のプログラムで戻ります localTime.cpp Unix 時間.

// localTime.cpp

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

int main() {

 std::cout << std::endl;

 using namespace date;
 
 std::cout << "UTC time" << std::endl; // (1)
 auto utcTime = std::chrono::system_clock::now();
 std::cout << " " << utcTime << std::endl;
 std::cout << " " << date::floor<std::chrono::seconds>(utcTime) << '\n':

 std::cout << std::endl;
 
 std::cout << "Local time" << std::endl; // (2)
 auto localTime = date::make_zoned(date::current_zone(), utcTime);
 std::cout << " " << localTime << std::endl;
 std::cout << " " << date::floor<std::chrono::seconds>(localTime.get_local_time()) 
 << std::endl;

 auto offset = localTime.get_info().offset; // (3)
 std::cout << " UTC offset: " << offset << std::endl;

 std::cout << std::endl;

}

プログラムに多くを追加する必要はありません。行 (1) で始まるコード ブロックは、現在の時点を取得し、秒単位で切り捨てて表示します。コール date::make_zoned std::chrono::zoned_time localTime. T を作成します 次の呼び出し localTime.get_local_time() 保存された時点を現地時間として返します。この時点も秒単位で切り捨てられます。 localTime (3 行目) を使用して、タイム ゾーンに関する情報を取得することもできます。この場合、UTC 時間へのオフセットに関心があります。

前回のプログラムは、別のタイム ゾーンで教えているときの重要な質問に答えます。オンライン クラスはいつ開始する必要がありますか?

オンライン クラスのさまざまなタイム ゾーン

プログラム onlineClass.cpp 次の質問に答えます:7h, 13h, にオンライン クラスを開始すると、特定のタイム ゾーンでどれくらい遅くなりますか? または 17h 現地時間 (ドイツ)?

オンライン クラスは 2021 年 2 月 1 日に開始する必要があり、所要時間は 4 時間です。夏時間のため、正しい答えを得るにはカレンダーの日付が不可欠です。

// onlineClass.cpp

#include "date/tz.h"
#include <algorithm>
#include <iomanip>
#include <iostream>

template <typename ZonedTime>
auto getMinutes(const ZonedTime& zonedTime) { // (1)
 return date::floor<std::chrono::minutes>(zonedTime.get_local_time());
}

void printStartEndTimes(const date::local_days& localDay, // (2)
 const std::chrono::hours& h, 
 const std::chrono::hours& durationClass,
 const std::initializer_list<std::string>& timeZones ){
 
 date::zoned_time startDate{date::current_zone(), localDay + h}; // (4)
 date::zoned_time endDate{date::current_zone(), localDay + h + durationClass};
 std::cout << "Local time: [" << getMinutes(startDate) << ", " 
 << getMinutes(endDate) << "]" << std::endl;
// (5)
longestStringSize = std::max(timeZones, [](const std::string& a, const std::string& b) { return a.size() < b.size(); }).size(); for (auto timeZone: timeZones) { // (6) std::cout << " " << std::setw(longestStringSize + 1) << std::left << timeZone << "[" << getMinutes(date::zoned_time(timeZone, startDate)) << ", " << getMinutes(date::zoned_time(timeZone, endDate)) << "]" << std::endl; } } int main() { using namespace std::string_literals; using namespace std::chrono; std::cout << std::endl; constexpr auto classDay{date::year(2021)/2/1}; constexpr auto durationClass = 4h; auto timeZones = {"America/Los_Angeles"s, "America/Denver"s, "America/New_York"s, "Europe/London"s, "Europe/Minsk"s, "Europe/Moscow"s, "Asia/Kolkata"s, "Asia/Novosibirsk"s, "Asia/Singapore"s, "Australia/Perth"s, "Australia/Sydney"s}; for (auto startTime: {7h, 13h, 17h}) { // (3) printStartEndTimes(date::local_days{classDay}, startTime, durationClass, timeZones); std::cout << std::endl; } }

関数に飛び込む前に getMinutes (1 行目) と printStartEndTimes (2 行目) main について一言言いましょう 関数。 main 関数は、クラスの日、クラスの期間、およびすべてのタイム ゾーンを定義します。最後に、範囲ベースの for ループ (3 行目) は、オンライン クラスのすべての潜在的な開始点を反復処理します。関数 printStartEndTimes のおかげで (2 行目) 必要なすべての情報が表示されます。

行 (4) から始まる数行は、 startDate を計算します。 と endDate クラスの開始時刻と期間をカレンダーの日付に追加することで、私のトレーニングの両方の値は、関数 getMinutes を使用して表示されます (ライン1)。 date::floor<std::chrono::minutes>(zonedTime.get_local_time()) std::chrono::zoned_time から保存された時点を取得します 値を分単位で切り捨てます。プログラムの出力を適切に配置するには、行 (5) すべてのタイムゾーン名の中で最も長い名前のサイズを決定します。行 (6) は、すべてのタイム ゾーンを反復し、タイム ゾーンの名前と、各オンライン クラスの開始と終了を表示します。いくつかのカレンダーの日付は、日の境界をまたいでいます。

拡張された Chrono ライブラリには、さらに多くのことを書く必要があります。たとえば、C++20 は std::chrono::utc_clock などの新しいクロックを提供します うるう秒を含む、または std::chrono::tai_clock これは、国際原子時 (TAI) を表します。さらに、C++20 の新しい書式設定ライブラリのおかげで、期間を適切に書式設定できます。この機能は今のところ利用できません。期間のフォーマット規則を調べたい場合は、std::formatter をご覧ください。

次は?

符号付き積分と符号なし積分を比較したい場合は、とても楽しいかもしれません。この楽しみは C++20 で終わります。