先日の記事でBoostをインストールできたのでBoostのライブラリを使って遊んでみましょう。
今回は日付に関する情報をBoostから取得・表示したり、〇月〇日~□月□日が何日間あるか(期間)取得してみましょう。
日付を利用するには gregorian.hpp と libboost_date_time.lib が必要です。
ヘッダーファイルと静的ライブラリの生成についてはこちらの記事を確認してみて下さいネ。
Contents
何が必要なのか確認しよう!
では具体的にBoostの日付を利用するためにはどのファイルが必要になるのでしょうか。
ライブラリ(debug版) | libboost_date_time-vc141-mt-gd-1_64.lib |
ライブラリ(Release版) | libboost_date_time-vc141-mt-1_64.lib |
ヘッダーファイル | boost/date_time/gregorian/gregorian.hpp |
** ビルド時の環境によってライブラリファイル名が異なります。
** 私のビルド時はVisual Studio 2017環境だったため、”vc141″が含まれています。
サンプルプログラムを作ってみよう!
先にサンプルプログラムを見て実際にプログラムを作ってみましょう。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
#include <iostream> #include <boost/date_time/gregorian/gregorian.hpp> int main() { // 今日の日付 const boost::gregorian::date today = boost::gregorian::day_clock::local_day(); // 特定の日付 const boost::gregorian::date newYearsDay(today.year(), 1, 1); // 文字列から日付を作る(区切り文字あり) const boost::gregorian::date christmas = boost::gregorian::from_string("2017/12/25"); // 文字列から日付を作る(区切り文字なし) const boost::gregorian::date birthday = boost::gregorian::from_undelimited_string("20170724"); // 文字列への変換 // ex). "2017-Jul-08" std::string strToday1 = boost::gregorian::to_simple_string(today); // ex). "20170808" std::string strToday2 = boost::gregorian::to_iso_string(today); // ex). "2017-07-08" std::string strToday3 = boost::gregorian::to_iso_extended_string(today); // 2つの日付から期間を得る // ex). (2017-07-08) - (2017-01-01) = 188日間 boost::gregorian::date_duration theDateDuration = today - newYearsDay; // ex). (2017-01-01) + 188日間 = (2017-07-08) boost::gregorian::date isToday = newYearsDay + theDateDuration; return 0; } |
** サンプルプログラムでは名前空間をすべて記述していますが、実際に利用する場合は using namespace を使って少しでも見やすくなるようにした方が良さそうです。
** もちろん名前の競合には気を付けてくださいネ。
どんな場合に使えるか考えてみる!
うーん、出力するファイル名に付与して日ごとのファイル管理などにも使えるでしょうか。
他にも処理日と処理内容をリスト化して表示する場合などで日付を扱いたくなる場合もありそうですネ。
この場合だと処理日から〇日間経過したら自動的に削除するなどで期間の計算なども必要になりそうです。
MFCなどで同じことをする場合は、CTimeクラスを使って日付を取得したり、CTime::Format関数でCString型を取得する感じになるでしょうか?
CTimeとboost::gregorian::date、どっちが早い?
そもそもCTimeは時刻もデータとして持っているので、boost::gregorian::dateの方が速そうな感じがします。
ざっくりしたテキトーなコードで確認してみます。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
void CDateSpeedDlg::OnBnClickedBtnCalculate() { const int loop_count = 1; using namespace std::chrono; auto start = system_clock::now(); for (int i = 0; i < loop_count; ++i) { CTime cTime = CTime::GetCurrentTime(); CString date = cTime.Format(_T("%Y-%B-%d")); } auto end = system_clock::now(); auto dur = end - start; auto nsec1 = duration_cast<nanoseconds>(dur).count(); // -------------------------------------------------------- using namespace boost::gregorian; start = system_clock::now(); for (int i = 0; i < loop_count; ++i) { const date today = day_clock::local_day(); std::string date = to_iso_extended_string(today); } end = system_clock::now(); dur = end - start; auto nsec2 = duration_cast<nanoseconds>(dur).count(); CString msg; msg.Format(_T("CTime : %lld, boost::date : %lld\ndiff : %lld"), nsec1, nsec2, (nsec2 > nsec1) ? nsec2 - nsec1 : nsec1 - nsec2); AfxMessageBox(msg); } |
1回目(ナノ秒) | 2回目 | 3回目 | 4回目 | 5回目 | 平均 | |
CTime(loop:1) | 521,600 | 9,900 | 19,600 | 7,000 | 6,400 | 112,900 |
boost(loop:1) | 73,700 | 21,500 | 18,000 | 13,800 | 13,100 | 28,020 |
CTime(loop:1,000) | 901,900 | 484,700 | 483,900 | 489,100 | 483,800 | 568,680 |
boost(loop:1,000) | 2,558,600 | 2,488,000 | 2,604,400 | 2,484,900 | 2,495,000 | 2,526,180 |
最適化の関係なのかCTimeでは初回に時間がかかりますが、その後は圧倒的に早いですね。
boost::gregorian::dateは1回ごとの速度に大きな差がないですが、比較すると遅く見えます。
ただし、今日の日付を1,000回確認するなんてことは実際にはないはずで、1度だけの確認で考えればboostの方が使いやすいように思います。
環境依存が少ない点も考慮すればCTimeからboostへの置換も十分検討の余地がありそうですネ。
まとめ
アプリケーションを作るときに日付が!って悩むことは多くないですが、あるとちょっとだけ助かる場合は多いですよね。
単純に日付が欲しいだけであれば std::time を使った方が速度も早いですが日付を文字列に変換したり、文字列を日付に変換したり、期間を得たいといった場合はライブラリを使うと楽に操作できるかもしれませんネ。