From 337a671f0c9749c38fb0e586bbdd25a1ff8f4719 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Fri, 21 Apr 2017 12:56:39 +0900 Subject: [PATCH] split datetime definition from toml.hpp --- tests/CMakeLists.txt | 1 + tests/test_datetime.cpp | 23 ++++ toml/datetime.hpp | 230 ++++++++++++++++++++++++++++++++++++++++ toml/toml.hpp | 49 +-------- 4 files changed, 257 insertions(+), 46 deletions(-) create mode 100644 tests/test_datetime.cpp create mode 100644 toml/datetime.hpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7200305..0077748 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,6 +5,7 @@ set(TEST_NAMES test_from_toml test_get test_value_operator + test_datetime ) add_definitions("-Wall -Wpedantic") diff --git a/tests/test_datetime.cpp b/tests/test_datetime.cpp new file mode 100644 index 0000000..fc3a4f0 --- /dev/null +++ b/tests/test_datetime.cpp @@ -0,0 +1,23 @@ +#define BOOST_TEST_MODULE "test_datetime" +#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST +#include +#else +#define BOOST_TEST_NO_LIB +#include +#endif +#include + +BOOST_AUTO_TEST_CASE(test_datetime_convertible) +{ + const auto now = std::chrono::system_clock::now(); + toml::Datetime d1(now); + const std::chrono::system_clock::time_point cvt(d1); + toml::Datetime d2(cvt); + + const auto time = std::chrono::system_clock::to_time_t(now); + toml::Datetime d3(time); + toml::Datetime d4(std::chrono::system_clock::from_time_t(time)); + + BOOST_CHECK_EQUAL(d1, d2); + BOOST_CHECK_EQUAL(d3, d4); +} diff --git a/toml/datetime.hpp b/toml/datetime.hpp new file mode 100644 index 0000000..94f80ec --- /dev/null +++ b/toml/datetime.hpp @@ -0,0 +1,230 @@ +#ifndef TOML11_DATETIME +#define TOML11_DATETIME +#include +#include +#include +#include + +namespace toml +{ + +template +struct basic_datetime +{ + constexpr static unsignedT undef = std::numeric_limits::max(); + constexpr static intT nooffset = std::numeric_limits::max(); + + unsignedT year; + unsignedT month; + unsignedT day; + unsignedT hour; + unsignedT minute; + unsignedT second; + unsignedT millisecond; + unsignedT microsecond; + intT offset_hour; + intT offset_minute; + + basic_datetime() = default; + ~basic_datetime() = default; + basic_datetime(const basic_datetime&) = default; + basic_datetime(basic_datetime&&) = default; + basic_datetime& operator=(const basic_datetime&) = default; + basic_datetime& operator=(basic_datetime&&) = default; + + basic_datetime(unsignedT y, unsignedT m, unsignedT d) + : year(y), month(m), day(d), hour(undef), minute(undef), second(undef), + millisecond(undef), microsecond(undef), + offset_hour(nooffset), offset_minute(nooffset) + {} + basic_datetime(unsignedT h, unsignedT m, unsignedT s, unsignedT ms, unsignedT us) + : year(undef), month(undef), day(undef), hour(h), minute(m), second(s), + millisecond(ms), microsecond(us), + offset_hour(nooffset), offset_minute(nooffset) + {} + basic_datetime(unsignedT y, unsignedT mth, unsignedT d, + unsignedT h, unsignedT min, unsignedT s, + unsignedT ms, unsignedT us) + : year(y), month(mth), day(d), hour(h), minute(min), second(s), + millisecond(ms), microsecond(us), + offset_hour(nooffset), offset_minute(nooffset) + {} + basic_datetime(unsignedT y, unsignedT mth, unsignedT d, + unsignedT h, unsignedT min, unsignedT s, + unsignedT ss, unsignedT us, intT oh, intT om) + : year(y), month(mth), day(d), hour(h), minute(min), second(s), + millisecond(ss), microsecond(us), offset_hour(oh), offset_minute(om) + {} + + basic_datetime(std::chrono::system_clock::time_point tp); + basic_datetime(std::time_t t); + + operator std::chrono::system_clock::time_point() const + { + std::tm time; + if(this->year == undef || this->month == undef || this->day == undef) + { + const auto now = std::chrono::system_clock::now(); + const auto t = std::chrono::system_clock::to_time_t(now); + std::tm* t_ = std::localtime(&t); + time.tm_year = t_->tm_year; + time.tm_mon = t_->tm_mon; + time.tm_mday = t_->tm_mday; + } + else + { + time.tm_year = this->year - 1900; + time.tm_mon = this->month - 1; + time.tm_mday = this->day; + } + time.tm_hour = (this->hour == undef) ? 0 : this->hour; + time.tm_min = (this->minute == undef) ? 0 : this->minute; + time.tm_sec = (this->second == undef) ? 0 : this->second; + + auto tp = std::chrono::system_clock::from_time_t(mktime(&time)); + tp += std::chrono::milliseconds(this->millisecond); + tp += std::chrono::microseconds(this->microsecond); + + if(this->offset_hour != nooffset && this->offset_minute != nooffset) + { + tp += std::chrono::hours(this->offset_hour); + tp += std::chrono::minutes(this->offset_minute); + } + return tp; + } + operator std::time_t() const + { + return std::chrono::system_clock::to_time_t( + std::chrono::system_clock::time_point(*this)); + } +}; + +template +basic_datetime::basic_datetime(std::chrono::system_clock::time_point tp) +{ + const auto t = std::chrono::system_clock::to_time_t(tp); + std::tm *time = std::localtime(&t); + this->year = time->tm_year + 1900; + this->month = time->tm_mon + 1; + this->day = time->tm_mday; + this->hour = time->tm_hour; + this->minute = time->tm_min; + this->second = time->tm_sec; + auto t_ = std::chrono::system_clock::from_time_t(std::mktime(time)); + auto diff = tp - t_; + this->millisecond = std::chrono::duration_cast(diff).count() % 1000; + this->microsecond = std::chrono::duration_cast(diff).count() % 1000; + + std::tm *utc = std::gmtime(&t); + + offset_hour = this->hour - utc->tm_hour; + offset_minute = this->minute - utc->tm_min; +} + +template +basic_datetime::basic_datetime(std::time_t t) +{ + *this = basic_datetime(std::chrono::system_clock::from_time_t(t)); +} + + +template +std::basic_ostream& +operator<<(std::basic_ostream& os, basic_datetime const& dt) +{ + bool date = false; + if(dt.year != basic_datetime::undef && + dt.month != basic_datetime::undef && + dt.day != basic_datetime::undef) + { + os << std::setfill('0') << std::setw(4) << dt.year << '-' + << std::setfill('0') << std::setw(2) << dt.month << '-' + << std::setfill('0') << std::setw(2) << dt.day; + date = true; + } + if(dt.hour != basic_datetime::undef && + dt.minute != basic_datetime::undef && + dt.second != basic_datetime::undef) + { + if(date) os << 'T'; + os << std::setfill('0') << std::setw(2) << dt.hour << ':' + << std::setfill('0') << std::setw(2) << dt.minute << ':' + << std::setfill('0') << std::setw(2) << dt.second << '.' + << std::setfill('0') << std::setw(3) << dt.millisecond + << std::setfill('0') << std::setw(3) << dt.microsecond; + } + if(dt.offset_hour != basic_datetime::nooffset && + dt.offset_minute != basic_datetime::nooffset) + { + if(dt.offset_hour == 0 && dt.offset_minute == 0) + { + os << 'Z'; + } + else + { + char sign = ' '; + iT oh = dt.offset_hour; + iT om = dt.offset_minute; + om += oh * 60; + if(om > 0) sign = '+'; else sign='-'; + oh = om / 60; + om -= oh * 60; + os << sign << std::setfill('0') << std::setw(2) << oh << ':' + << std::setfill('0') << std::setw(2) << om; + } + } + return os; +} + +template +inline bool +operator==(basic_datetime const& lhs, basic_datetime const& rhs) +{ + return lhs.year == rhs.year && lhs.month == rhs.month && + lhs.day == rhs.day && lhs.minute == rhs.minute && + lhs.second == rhs.second && lhs.millisecond == rhs.millisecond && + lhs.microsecond == rhs.microsecond && + lhs.offset_hour == rhs.offset_hour && + lhs.offset_minute == rhs.offset_minute; +} + +template +inline bool +operator!=(basic_datetime const& lhs, basic_datetime const& rhs) +{ + return !(lhs == rhs); +} + +template +inline bool +operator<(basic_datetime const& lhs, basic_datetime const& rhs) +{ + return std::time_t(lhs) < std::time_t(rhs); +} + +template +inline bool +operator<=(basic_datetime const& lhs, basic_datetime const& rhs) +{ + return std::time_t(lhs) <= std::time_t(rhs); +} + +template +inline bool +operator>(basic_datetime const& lhs, basic_datetime const& rhs) +{ + return std::time_t(lhs) > std::time_t(rhs); +} + +template +inline bool +operator>=(basic_datetime const& lhs, basic_datetime const& rhs) +{ + return std::time_t(lhs) >= std::time_t(rhs); +} + + +}//toml +#endif// TOML11_DATETIME diff --git a/toml/toml.hpp b/toml/toml.hpp index 9c04747..bbfdbf0 100644 --- a/toml/toml.hpp +++ b/toml/toml.hpp @@ -24,6 +24,7 @@ #ifndef TOML_FOR_MODERN_CPP #define TOML_FOR_MODERN_CPP +#include "datetime.hpp" #include #include #include @@ -32,56 +33,12 @@ #include #include #include -#include -#include -#include #include +#include namespace toml { -template -struct basic_datetime -{ - unsignedT year; - unsignedT month; - unsignedT day; - unsignedT hour; - unsignedT minute; - unsignedT second; - floatT subsecond; - intT offset_hour; - intT offset_minute; - - basic_datetime(intT y, intT m, intT d) - : year(y), month(m), day(d), hour(0), minute(0), second(0), - subsecond(0.), offset_hour(0), offset_minute(0) - {} - basic_datetime(intT h, intT m, intT s, floatT ss) - : year(0), month(0), day(0), hour(h), minute(m), second(s), - subsecond(ss), offset_hour(0), offset_minute(0) - {} - basic_datetime(intT y, intT mth, intT d, - intT h, intT min, intT s, floatT ss) - : year(y), month(mth), day(d), hour(h), minute(min), second(s), - subsecond(ss), offset_hour(0), offset_minute(0) - {} - basic_datetime(intT y, intT mth, intT d, - intT h, intT min, intT s, floatT ss, intT oh, intT om) - : year(y), month(mth), day(d), hour(h), minute(min), second(s), - subsecond(ss), offset_hour(oh), offset_minute(om) - {} - - basic_datetime(const std::chrono::system_clock::time_point& tp); - basic_datetime(std::chrono::system_clock::time_point&& tp); - - operator std::chrono::system_clock::time_point() const; - operator std::time_t() const; - operator std::tm() const; -}; - -typedef basic_datetime Datetime; - class value; using key = std::string; @@ -89,7 +46,7 @@ using Boolean = bool; using Integer = std::int64_t; using Float = double; using String = std::string; -using Datetime = std::chrono::system_clock::time_point; +using Datetime = basic_datetime; using Array = std::vector; using Table = std::unordered_map;