「C++の基礎 - 時刻」の版間の差分
編集の要約なし |
|||
| 4行目: | 4行目: | ||
== 本日の経過時刻の取得 == | == 本日の経過時刻の取得 == | ||
==== std::chrono ==== | ==== std::chrono (C++11) ==== | ||
本日の0時0分0秒000からの経過時刻 (mS) を求めるには、<code>std::chrono</code> (C++11以降) を使用する。<br> | 本日の0時0分0秒000からの経過時刻 (mS) を求めるには、<code>std::chrono</code> (C++11以降) を使用する。<br> | ||
なお、C++17以降およびLinux環境では別の手段も存在する。<br> | なお、C++17以降およびLinux環境では別の手段も存在する。<br> | ||
| 80行目: | 80行目: | ||
// 指定されたタイムポイントを文字列形式に変換する | // 指定されたタイムポイントを文字列形式に変換する | ||
// オフセットを適用してタイムゾーンを調整する | // オフセットを適用してタイムゾーンを調整する | ||
std::string format_time(const std::chrono::system_clock::time_point& tp, int offset = 0) | std::string format_time(const std::chrono::system_clock::time_point &tp, int offset = 0) | ||
{ | { | ||
auto time = std::chrono::system_clock::to_time_t(tp) + offset; | auto time = std::chrono::system_clock::to_time_t(tp) + offset; | ||
| 93行目: | 93行目: | ||
// 指定されたタイムポイントの日の開始時刻 (00:00:00.000) を計算する | // 指定されたタイムポイントの日の開始時刻 (00:00:00.000) を計算する | ||
// タイムゾーンのオフセットも考慮する | // タイムゾーンのオフセットも考慮する | ||
std::chrono::system_clock::time_point get_day_start(const std::chrono::system_clock::time_point& tp, int offset = 0) | std::chrono::system_clock::time_point get_day_start(const std::chrono::system_clock::time_point &tp, int offset = 0) | ||
{ | { | ||
auto time = std::chrono::system_clock::to_time_t(tp) + offset; | auto time = std::chrono::system_clock::to_time_t(tp) + offset; | ||
| 103行目: | 103行目: | ||
// 指定されたタイムゾーンの現在時刻と経過時間を表示する | // 指定されたタイムゾーンの現在時刻と経過時間を表示する | ||
void print_time_info(const std::string& zone_name, const std::chrono::system_clock::time_point& tp, int offset = 0) | void print_time_info(const std::string &zone_name, const std::chrono::system_clock::time_point &tp, int offset = 0) | ||
{ | { | ||
auto day_start = get_day_start(tp, offset); | auto day_start = get_day_start(tp, offset); | ||
| 143行目: | 143行目: | ||
<u>より正確な時間を取得する場合は、タイムゾーンライブラリ (例: Howard Hinnant's dateライブラリ等) の使用を推奨する。</u><br> | <u>より正確な時間を取得する場合は、タイムゾーンライブラリ (例: Howard Hinnant's dateライブラリ等) の使用を推奨する。</u><br> | ||
<br> | <br> | ||
C++20では、<code>std::chrono::month</code>や<code>std::chrono::year</code> | ==== std::chrono (C++17) ==== | ||
C++17以降では、<code><chrono></code>ライブラリに大幅な拡張が加えられており、タイムゾーンやカレンダーの扱いが簡単になった。<br> | |||
特に、<code>std::chrono::zoned_time</code>クラスの導入により、タイムゾーンを考慮した時間の扱いが可能になった。<br> | |||
以下の例では、C++17の新機能を使用して、UTC時間、日本時間、フランス時間の3つのタイムゾーンで現在時刻と本日の経過時間を表示している。<br> | |||
<br> | |||
処理の流れを以下に示す。 | |||
# <code>zoned_time</code>クラスを使用して、特定のタイムゾーンでの時間を表現する。 | |||
# <code>floor<days></code>を使用して、その日の開始時刻 (午前0時) を計算する。 | |||
# <code>duration_cast</code>を使用して、経過時間をミリ秒単位で計算する。 | |||
# タイムゾーンは文字列で指定する。 ("UTC", "Asia/Tokyo", "Europe/Paris")<br>これにより、夏時間なども自動的に考慮される。 | |||
# タイムゾーンが見つからない場合等はエラーとする。 | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
#include <iostream> | |||
#include <chrono> | |||
#include <iomanip> | |||
using namespace std::chrono; | |||
template<typename Clock, typename Duration> | |||
void print_time_info(const std::string &zone_name, const zoned_time<Duration> &zt) | |||
{ | |||
auto now = zt.get_local_time(); | |||
auto today = floor<days>(now); | |||
auto time_since_midnight = now - today; | |||
std::cout << zone_name << ":\n"; | |||
std::cout << " 現在時刻: " << now << "\n"; | |||
std::cout << " 経過時間: " << duration_cast<milliseconds>(time_since_midnight).count() << " ms\n\n"; | |||
} | |||
int main() | |||
{ | |||
try { | |||
// 現在のUTC時間を取得 | |||
auto now = system_clock::now(); | |||
// 各タイムゾーンでの時間を計算 | |||
auto utc = zoned_time<milliseconds>("UTC", now); | |||
auto tokyo = zoned_time<milliseconds>("Asia/Tokyo", now); | |||
auto paris = zoned_time<milliseconds>("Europe/Paris", now); | |||
// 各タイムゾーンの情報を表示 | |||
print_time_info("UTC", utc); | |||
print_time_info("日本時間", tokyo); | |||
print_time_info("フランス時間", paris); | |||
} | |||
catch (const std::exception &e) { | |||
std::cerr << "エラー: " << e.what() << std::endl; | |||
return -1; | |||
} | |||
return 0; | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
# 出力例 | |||
UTC: | |||
現在時刻: 2024-09-05 05:30:45.123456 | |||
経過時間: 19845123 ms | |||
日本時間: | |||
現在時刻: 2024-09-05 14:30:45.123456 | |||
経過時間: 52245123 ms | |||
フランス時間: | |||
現在時刻: 2024-09-05 07:30:45.123456 | |||
経過時間: 27045123 ms | |||
<br> | |||
==== std::chrono (C++20) ==== | |||
C++20では、<code>std::chrono::month</code>や<code>std::chrono::year</code>が追加されたため、月初めからや年頭からの経過時刻 (mS) を取得することができる。<br> | |||
また、C++20では、現地時刻用の<code>time_point</code>型、今日の時間情報を取得する<code>time_of_day</code>クラスも追加されるため、<code>time_t</code>型に変換せずに簡単に取得できる。<br> | また、C++20では、現地時刻用の<code>time_point</code>型、今日の時間情報を取得する<code>time_of_day</code>クラスも追加されるため、<code>time_t</code>型に変換せずに簡単に取得できる。<br> | ||
<br> | |||
C++20での主な改善点を以下に示す。<br> | |||
* カレンダーと時間帯のサポートの強化された。 | |||
* 日付の操作がより直感的になった。 | |||
* 時間帯データベースへのアクセスが改善された。 | |||
* 書式化機能が強化されて、日付と時間の出力がより柔軟になった。 | |||
<br> | |||
C++20の時間関連機能において、複雑な日付と時間の操作を含むアプリケーションの開発が大幅に簡素化された。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
#include <iostream> | |||
#include <chrono> | |||
#include <format> | |||
using namespace std::chrono; | |||
template<typename Clock, typename Duration> | |||
void print_time_info(const std::string &zone_name, const zoned_time<Duration> &zt) | |||
{ | |||
auto now = zt.get_local_time(); | |||
auto today = floor<days>(now); | |||
auto time_since_midnight = now - today; | |||
auto ymd = year_month_day{today}; | |||
auto time = hh_mm_ss{floor<milliseconds>(time_since_midnight)}; | |||
std::cout << std::format("{}: \n", zone_name); | |||
std::cout << std::format(" 現在時刻: {:%Y-%m-%d %H:%M:%S}.{:03d}\n", now, time.subseconds().count()); | |||
std::cout << std::format(" 経過時間: {} ms\n\n", duration_cast<milliseconds>(time_since_midnight).count()); | |||
} | |||
int main() | |||
{ | |||
try { | |||
// 現在のシステム時間を取得 | |||
auto now = system_clock::now(); | |||
// タイムゾーンオブジェクトを取得 | |||
const auto utc = locate_zone("UTC"); | |||
const auto tokyo = locate_zone("Asia/Tokyo"); | |||
const auto paris = locate_zone("Europe/Paris"); | |||
// 各タイムゾーンでの時間を計算 | |||
auto utc_time = zoned_time{utc, now}; | |||
auto tokyo_time = zoned_time{tokyo, now}; | |||
auto paris_time = zoned_time{paris, now}; | |||
// 各タイムゾーンの情報を表示 | |||
print_time_info("UTC", utc_time); | |||
print_time_info("日本時間", tokyo_time); | |||
print_time_info("フランス時間", paris_time); | |||
// 日付操作の例 | |||
auto today = floor<days>(utc_time.get_local_time()); | |||
auto this_year = year_month_day{today}.year(); | |||
auto new_years_day = sys_days{this_year/January/1}; | |||
auto days_since_new_year = floor<days>(utc_time.get_sys_time() - new_years_day); | |||
std::cout << std::format("今年の元旦から今日までの日数: {} 日\n", days_since_new_year.count()); | |||
} | |||
catch (const std::exception &e) { | |||
std::cerr << "エラー: " << e.what() << std::endl; | |||
return -1; | |||
} | |||
return 0; | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
# 出力例 | |||
UTC: | |||
現在時刻: 2024-09-05 05:30:45.123 | |||
経過時間: 19845123 ms | |||
日本時間: | |||
現在時刻: 2024-09-05 14:30:45.123 | |||
経過時間: 52245123 ms | |||
フランス時間: | |||
現在時刻: 2024-09-05 07:30:45.123 | |||
経過時間: 27045123 ms | |||
今年の元旦から今日までの日数: 249 日 | |||
<br> | |||
<u>※注意</u><br> | |||
<u>一部の機能 (特にタイムゾーン関連) は、使用する実装によっては、まだ完全にはサポートされていない可能性がある。</u><br> | |||
<br><br> | <br><br> | ||
__FORCETOC__ | __FORCETOC__ | ||
[[カテゴリ:C++]] | [[カテゴリ:C++]] | ||
2024年9月5日 (木) 04:03時点における版
概要
本日の経過時刻の取得
std::chrono (C++11)
本日の0時0分0秒000からの経過時刻 (mS) を求めるには、std::chrono (C++11以降) を使用する。
なお、C++17以降およびLinux環境では別の手段も存在する。
現在時刻に関する情報は、std::chronoのnowメソッドで取得できる。
なお、この時刻はUTC (協定世界時) であり日本時間とは異なることに注意する。
#include <chrono>
std::chrono::system_clock::time_point tp = std::chrono::system_clock::now();
まず、time_since_epocメソッドを使用して、エポックタイムからの経過時刻を取得した後、countメソッドでミリ秒を取得する。
取得した値から現在時刻のミリ秒の部分を得る。
エポックタイムは、未規定ではあるが概ね1970年1月1日から始まる。
ただし、経過時刻 (mS) は1兆を超える値になるため、32ビットのint型では格納できないことに注意する。
// エポックタイムからの経過時刻
std::chrono::milliseconds tp_msec = std::chrono::duration_cast<std::chrono::milliseconds>(tp.time_since_epoch());
// 経過時刻をミリ秒 (整数値) に変換する
long long all_msec = tp_msec.count();
// 1秒未満の値を取り出す
int msec = all_msec % 1000;
時間、分、秒を取得するため、time_t型に変換する。
さらに、現地時間 (日本時間) に変換する。
time_t time = std::chrono::system_clock::to_time_t(tp);
struct tm* t = localtime(&time);
この時、本日の経過時刻 (mS) は計算できるが、std::chrono::system_clock::time_point型は減算ができるため、本日の0時0分0秒000のタイムスタンプを求める。
// 本日0時0分0秒000のtime_pointを求める
std::chrono::system_clock::time_point day_tp = tp;
// 0時にする
day_tp -= std::chrono::hours(t->tm_hour);
// 0分にする
day_tp -= std::chrono::minutes(t->tm_min);
// 0秒にする
day_tp -= std::chrono::seconds(t->tm_sec);
// コンマ0秒にする
day_tp -= std::chrono::milliseconds(msec);
time_point型同士で減算した後、本日の経過時刻 (mS) を求める。
std::chrono::milliseconds tp_msec_today = std::chrono::duration_cast<std::chrono::milliseconds>(tp - day_tp);
int msec_today = tp_msec_today.count();
以下の例では、UTC時間、日本時間、フランス時間の3つのタイムゾーンで現在時刻と本日の経過時間を表示している。
以下の例は夏時間を考慮していないため、実務では、タイムゾーンライブラリ (例: Howard Hinnant's dateライブラリ等) の使用を検討すること。
(フランスの時差は、一般的に、UTC+1 であるが、夏時間中は UTC+2 となる)
#include <iostream>
#include <chrono>
#include <ctime>
#include <iomanip>
// タイムゾーンごとの時差 (秒)
const int JAPAN_OFFSET = 9 * 3600; // 日本時間
const int FRANCE_OFFSET = 1 * 3600; // フランス時間 (ただし、夏時間を考慮していないことに注意する)
// 指定されたタイムポイントを文字列形式に変換する
// オフセットを適用してタイムゾーンを調整する
std::string format_time(const std::chrono::system_clock::time_point &tp, int offset = 0)
{
auto time = std::chrono::system_clock::to_time_t(tp) + offset;
auto msec = std::chrono::duration_cast<std::chrono::milliseconds>(tp.time_since_epoch()).count() % 1000;
std::tm* t = std::gmtime(&time);
std::ostringstream oss;
oss << std::put_time(t, "%Y-%m-%d %H:%M:%S") << '.' << std::setfill('0') << std::setw(3) << msec;
return oss.str();
}
// 指定されたタイムポイントの日の開始時刻 (00:00:00.000) を計算する
// タイムゾーンのオフセットも考慮する
std::chrono::system_clock::time_point get_day_start(const std::chrono::system_clock::time_point &tp, int offset = 0)
{
auto time = std::chrono::system_clock::to_time_t(tp) + offset;
std::tm* t = std::gmtime(&time);
return tp - std::chrono::hours(t->tm_hour) - std::chrono::minutes(t->tm_min) - std::chrono::seconds(t->tm_sec)
- std::chrono::milliseconds(std::chrono::duration_cast<std::chrono::milliseconds>(tp.time_since_epoch()).count() % 1000)
- std::chrono::seconds(offset);
}
// 指定されたタイムゾーンの現在時刻と経過時間を表示する
void print_time_info(const std::string &zone_name, const std::chrono::system_clock::time_point &tp, int offset = 0)
{
auto day_start = get_day_start(tp, offset);
auto msec_today = std::chrono::duration_cast<std::chrono::milliseconds>(tp - day_start).count();
std::cout << zone_name << ":" << std::endl;
std::cout << " 現在時刻: " << format_time(tp, offset) << std::endl;
std::cout << " 経過時間: " << msec_today << " ms" << std::endl;
std::cout << std::endl;
}
int main()
{
auto now = std::chrono::system_clock::now();
print_time_info("UTC", now);
print_time_info("日本時間", now, JAPAN_OFFSET);
print_time_info("フランス時間", now, FRANCE_OFFSET); // フランス時間で
return 0;
}
# 出力例 UTC: 現在時刻: 2024-09-05 05:30:45.123 経過時間: 19845123 ms 日本時間: 現在時刻: 2024-09-05 14:30:45.123 経過時間: 52245123 ms フランス時間: 現在時刻: 2024-09-05 06:30:45.123 経過時間: 23445123 ms
※注意
より正確な時間を取得する場合は、タイムゾーンライブラリ (例: Howard Hinnant's dateライブラリ等) の使用を推奨する。
std::chrono (C++17)
C++17以降では、<chrono>ライブラリに大幅な拡張が加えられており、タイムゾーンやカレンダーの扱いが簡単になった。
特に、std::chrono::zoned_timeクラスの導入により、タイムゾーンを考慮した時間の扱いが可能になった。
以下の例では、C++17の新機能を使用して、UTC時間、日本時間、フランス時間の3つのタイムゾーンで現在時刻と本日の経過時間を表示している。
処理の流れを以下に示す。
zoned_timeクラスを使用して、特定のタイムゾーンでの時間を表現する。floor<days>を使用して、その日の開始時刻 (午前0時) を計算する。duration_castを使用して、経過時間をミリ秒単位で計算する。- タイムゾーンは文字列で指定する。 ("UTC", "Asia/Tokyo", "Europe/Paris")
これにより、夏時間なども自動的に考慮される。 - タイムゾーンが見つからない場合等はエラーとする。
#include <iostream>
#include <chrono>
#include <iomanip>
using namespace std::chrono;
template<typename Clock, typename Duration>
void print_time_info(const std::string &zone_name, const zoned_time<Duration> &zt)
{
auto now = zt.get_local_time();
auto today = floor<days>(now);
auto time_since_midnight = now - today;
std::cout << zone_name << ":\n";
std::cout << " 現在時刻: " << now << "\n";
std::cout << " 経過時間: " << duration_cast<milliseconds>(time_since_midnight).count() << " ms\n\n";
}
int main()
{
try {
// 現在のUTC時間を取得
auto now = system_clock::now();
// 各タイムゾーンでの時間を計算
auto utc = zoned_time<milliseconds>("UTC", now);
auto tokyo = zoned_time<milliseconds>("Asia/Tokyo", now);
auto paris = zoned_time<milliseconds>("Europe/Paris", now);
// 各タイムゾーンの情報を表示
print_time_info("UTC", utc);
print_time_info("日本時間", tokyo);
print_time_info("フランス時間", paris);
}
catch (const std::exception &e) {
std::cerr << "エラー: " << e.what() << std::endl;
return -1;
}
return 0;
}
# 出力例 UTC: 現在時刻: 2024-09-05 05:30:45.123456 経過時間: 19845123 ms 日本時間: 現在時刻: 2024-09-05 14:30:45.123456 経過時間: 52245123 ms フランス時間: 現在時刻: 2024-09-05 07:30:45.123456 経過時間: 27045123 ms
std::chrono (C++20)
C++20では、std::chrono::monthやstd::chrono::yearが追加されたため、月初めからや年頭からの経過時刻 (mS) を取得することができる。
また、C++20では、現地時刻用のtime_point型、今日の時間情報を取得するtime_of_dayクラスも追加されるため、time_t型に変換せずに簡単に取得できる。
C++20での主な改善点を以下に示す。
- カレンダーと時間帯のサポートの強化された。
- 日付の操作がより直感的になった。
- 時間帯データベースへのアクセスが改善された。
- 書式化機能が強化されて、日付と時間の出力がより柔軟になった。
C++20の時間関連機能において、複雑な日付と時間の操作を含むアプリケーションの開発が大幅に簡素化された。
#include <iostream>
#include <chrono>
#include <format>
using namespace std::chrono;
template<typename Clock, typename Duration>
void print_time_info(const std::string &zone_name, const zoned_time<Duration> &zt)
{
auto now = zt.get_local_time();
auto today = floor<days>(now);
auto time_since_midnight = now - today;
auto ymd = year_month_day{today};
auto time = hh_mm_ss{floor<milliseconds>(time_since_midnight)};
std::cout << std::format("{}: \n", zone_name);
std::cout << std::format(" 現在時刻: {:%Y-%m-%d %H:%M:%S}.{:03d}\n", now, time.subseconds().count());
std::cout << std::format(" 経過時間: {} ms\n\n", duration_cast<milliseconds>(time_since_midnight).count());
}
int main()
{
try {
// 現在のシステム時間を取得
auto now = system_clock::now();
// タイムゾーンオブジェクトを取得
const auto utc = locate_zone("UTC");
const auto tokyo = locate_zone("Asia/Tokyo");
const auto paris = locate_zone("Europe/Paris");
// 各タイムゾーンでの時間を計算
auto utc_time = zoned_time{utc, now};
auto tokyo_time = zoned_time{tokyo, now};
auto paris_time = zoned_time{paris, now};
// 各タイムゾーンの情報を表示
print_time_info("UTC", utc_time);
print_time_info("日本時間", tokyo_time);
print_time_info("フランス時間", paris_time);
// 日付操作の例
auto today = floor<days>(utc_time.get_local_time());
auto this_year = year_month_day{today}.year();
auto new_years_day = sys_days{this_year/January/1};
auto days_since_new_year = floor<days>(utc_time.get_sys_time() - new_years_day);
std::cout << std::format("今年の元旦から今日までの日数: {} 日\n", days_since_new_year.count());
}
catch (const std::exception &e) {
std::cerr << "エラー: " << e.what() << std::endl;
return -1;
}
return 0;
}
# 出力例 UTC: 現在時刻: 2024-09-05 05:30:45.123 経過時間: 19845123 ms 日本時間: 現在時刻: 2024-09-05 14:30:45.123 経過時間: 52245123 ms フランス時間: 現在時刻: 2024-09-05 07:30:45.123 経過時間: 27045123 ms 今年の元旦から今日までの日数: 249 日
※注意
一部の機能 (特にタイムゾーン関連) は、使用する実装によっては、まだ完全にはサポートされていない可能性がある。