Boost.DateTimeが使いにくかったので、日時計算を目的とした簡単なDateTimeライブラリを書きました。
SHAND_DATE_TIME_CUSTOM_NOW_TIMEをdefineすることで、現在日時を返す関数を書き換えることができるようになるので、Testableです。
フォーマット指定は、strftimeを参考に、よく使うものだけを採用しました。
shand/date_time.hpp
#ifndef SHAND_DATE_TIME_INCLUDE #define SHAND_DATE_TIME_INCLUDE #include <cstddef> #include <ctime> #include <map> #include <boost/xpressive/xpressive_static.hpp> #include <boost/xpressive/regex_actions.hpp> #include <boost/assign/list_of.hpp> #include <boost/format.hpp> #include <boost/lambda/lambda.hpp> namespace shand { template <int> class primitive { std::size_t value_; public: primitive() : value_(0) {} primitive(std::size_t value) : value_(value) {} std::size_t value() const { return value_; } }; typedef primitive<0> year; typedef primitive<1> month; typedef primitive<2> day; typedef primitive<3> hour; typedef primitive<4> minute; typedef primitive<5> second; #ifdef SHAND_DATE_TIME_CUSTOM_NOW_TIME std::time_t now_time_t(); #else inline std::time_t now_time_t() { std::time_t t; std::time(&t); return t; } #endif class date_time { std::time_t time_; template <class F> date_time& assign_time(F f) { std::time_t tmp = time_; std::tm* st = std::localtime(&tmp); f(st); time_ = std::mktime(st); return *this; } template <class F> static date_time calc_time(const date_time& d, F f) { std::time_t tmp = d.time_; std::tm* st = std::localtime(&tmp); f(st); return date_time(std::mktime(st)); } public: date_time() {} explicit date_time(std::time_t t) : time_(t) {} std::string format(const std::string& fmt) const { std::tm* st = std::localtime(&time_); const std::map<std::string, std::string> rep = boost::assign::list_of (std::make_pair("%Y", (boost::format("%04d") % (1900 + st->tm_year)).str())) (std::make_pair("%m", (boost::format("%02d") % (1 + st->tm_mon)).str())) (std::make_pair("%d", (boost::format("%02d") % st->tm_mday).str())) (std::make_pair("%H", (boost::format("%02d") % st->tm_hour).str())) (std::make_pair("%M", (boost::format("%02d") % st->tm_min).str())) (std::make_pair("%S", (boost::format("%02d") % st->tm_sec).str())) ; using namespace boost::xpressive; local<std::string const *> pstr; const sregex rx = (a1 = rep)[pstr = &a1]; return regex_replace(fmt, rx, *pstr); } static date_time now() { return date_time(now_time_t()); } time_t to_time_t() const { return time_; } // assign date_time& operator=(const year& x) { return assign_time(boost::lambda::_1 ->* &std::tm::tm_year = x.value() - 1900); } date_time& operator=(const month& x) { return assign_time(boost::lambda::_1 ->* &std::tm::tm_mon = x.value() - 1); } date_time& operator=(const day& x) { return assign_time(boost::lambda::_1 ->* &std::tm::tm_mday = x.value()); } date_time& operator=(const hour& x) { return assign_time(boost::lambda::_1 ->* &std::tm::tm_hour = x.value()); } date_time& operator=(const minute& x) { return assign_time(boost::lambda::_1 ->* &std::tm::tm_min = x.value()); } date_time& operator=(const second& x) { return assign_time(boost::lambda::_1 ->* &std::tm::tm_sec = x.value()); } // add friend date_time operator+(const date_time& d, const year& x) { return date_time::calc_time(d, boost::lambda::_1 ->* &std::tm::tm_year += x.value()); } friend date_time operator+(const date_time& d, const month& x) { return date_time::calc_time(d, boost::lambda::_1 ->* &std::tm::tm_mon += x.value()); } friend date_time operator+(const date_time& d, const day& x) { return date_time::calc_time(d, boost::lambda::_1 ->* &std::tm::tm_mday += x.value()); } friend date_time operator+(const date_time& d, const hour& x) { return date_time::calc_time(d, boost::lambda::_1 ->* &std::tm::tm_hour += x.value()); } friend date_time operator+(const date_time& d, const minute& x) { return date_time::calc_time(d, boost::lambda::_1 ->* &std::tm::tm_min += x.value()); } friend date_time operator+(const date_time& d, const second& x) { return date_time::calc_time(d, boost::lambda::_1 ->* &std::tm::tm_sec += x.value()); } // substract friend date_time operator-(const date_time& d, const year& x) { return date_time::calc_time(d, boost::lambda::_1 ->* &std::tm::tm_year -= x.value()); } friend date_time operator-(const date_time& d, const month& x) { return date_time::calc_time(d, boost::lambda::_1 ->* &std::tm::tm_mon -= x.value()); } friend date_time operator-(const date_time& d, const day& x) { return date_time::calc_time(d, boost::lambda::_1 ->* &std::tm::tm_mday -= x.value()); } friend date_time operator-(const date_time& d, const hour& x) { return date_time::calc_time(d, boost::lambda::_1 ->* &std::tm::tm_hour -= x.value()); } friend date_time operator-(const date_time& d, const minute& x) { return date_time::calc_time(d, boost::lambda::_1 ->* &std::tm::tm_min -= x.value()); } friend date_time operator-(const date_time& d, const second& x) { return date_time::calc_time(d, boost::lambda::_1 ->* &std::tm::tm_sec -= x.value()); } }; inline day diff_day(const date_time& a, const date_time& b) { const std::time_t& at = (std::max)(a.to_time_t(), b.to_time_t()); const std::time_t& bt = (std::min)(a.to_time_t(), b.to_time_t()); return day(static_cast<std::size_t>(std::difftime(at, bt) / (60 * 60 * 24))); } inline hour diff_hour(const date_time& a, const date_time& b) { const std::time_t& at = (std::max)(a.to_time_t(), b.to_time_t()); const std::time_t& bt = (std::min)(a.to_time_t(), b.to_time_t()); return hour(static_cast<std::size_t>(std::difftime(at, bt) / (60 * 60))); } inline minute diff_minute(const date_time& a, const date_time& b) { const std::time_t& at = (std::max)(a.to_time_t(), b.to_time_t()); const std::time_t& bt = (std::min)(a.to_time_t(), b.to_time_t()); return minute(static_cast<std::size_t>(std::difftime(at, bt) / 60)); } inline second diff_second(const date_time& a, const date_time& b) { const std::time_t& at = (std::max)(a.to_time_t(), b.to_time_t()); const std::time_t& bt = (std::min)(a.to_time_t(), b.to_time_t()); return second(static_cast<std::size_t>(std::difftime(at, bt))); } } // namespace shand #endif // SHAND_DATE_TIME_INCLUDE
テスト
#include <boost/detail/lightweight_test.hpp> #define SHAND_DATE_TIME_CUSTOM_NOW_TIME // 現在時間を返す関数を書き換える #include <shand/date_time.hpp> namespace shand { std::time_t now_time_t() { std::tm t; t.tm_year = 2010 - 1900; t.tm_mon = 12 - 1; t.tm_yday = 353; t.tm_mday = 20; t.tm_wday = 1; t.tm_hour = 15; t.tm_min = 30; t.tm_sec = 45; t.tm_isdst = 0; return std::mktime(&t); } } int main() { using namespace shand; // 現在日時をフォーマット指定して出力 BOOST_TEST(date_time::now().format("%Y/%m/%d %H:%M:%S") == "2010/12/20 15:30:45"); // 1年加算 { const date_time tm = date_time::now(); BOOST_TEST((tm + year(1)).format("%Y/%m/%d %H:%M:%S") == "2011/12/20 15:30:45"); } // 今月の日数を求める(次の月の1日から1日引く) { date_time tm = date_time::now(); BOOST_TEST((((tm + month(1)) = day(1)) - day(1)).format("%d") == "31"); } // 日数の差を計算 { date_time a = date_time::now(); ((a = year(2010)) = month(3)) = day(1); date_time b = date_time::now(); ((b = year(2010)) = month(3)) = day(5); BOOST_TEST(diff_day(a, b).value() == 4); } return boost::report_errors(); }