diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 0217c5e7..806cd9a0 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -37,6 +37,6 @@ if (WIN32) set(ADDITIONAL_LINK_LIBRARIES ws2_32) endif() link_libraries(OpenSSL::Crypto OpenSSL::SSL ${ADDITIONAL_LINK_LIBRARIES}) -add_compile_options(-Wno-deprecated) +add_compile_options(-Wno-deprecated -Wno-nonnull -Wno-deprecated-declarations) add_subdirectory(src/spot_market_making) add_subdirectory(src/single_order_execution) diff --git a/app/include/app/common.h b/app/include/app/common.h index 201e3693..c2f9a4e8 100644 --- a/app/include/app/common.h +++ b/app/include/app/common.h @@ -81,6 +81,7 @@ #include #include +#include "ccapi_cpp/ccapi_logger.h" #include "ccapi_cpp/ccapi_util_private.h" namespace ccapi { class AppUtil { diff --git a/app/include/app/historical_market_data_event_processor.h b/app/include/app/historical_market_data_event_processor.h index 3314750a..560b6780 100644 --- a/app/include/app/historical_market_data_event_processor.h +++ b/app/include/app/historical_market_data_event_processor.h @@ -17,7 +17,7 @@ class HistoricalMarketDataEventProcessor { bool shouldContinueTrade{true}; std::vector previousSplittedMarketDepth; while (currentDateTp < this->historicalMarketDataEndDateTp) { - const auto& currentDateISO = UtilTime::getISOTimestamp(currentDateTp, "%F"); + const auto& currentDateISO = UtilTime::getISOTimestamp(currentDateTp).substr(0, 10); APP_LOGGER_INFO("Start processing " + currentDateISO + "."); std::string fileNameWithDirBase = this->historicalMarketDataDirectory + "/" + this->historicalMarketDataFilePrefix + this->exchange + "__" + this->baseAsset + "-" + this->quoteAsset + "__" + currentDateISO + "__"; diff --git a/app/src/single_order_execution/main.cpp b/app/src/single_order_execution/main.cpp index 742a63f6..cea1444c 100644 --- a/app/src/single_order_execution/main.cpp +++ b/app/src/single_order_execution/main.cpp @@ -100,11 +100,11 @@ int main(int argc, char** argv) { eventHandler.marketImpfactFactor = UtilSystem::getEnvAsDouble("MARKET_IMPACT_FACTOR"); } if (eventHandler.tradingMode == EventHandlerBase::TradingMode::BACKTEST) { - eventHandler.historicalMarketDataStartDateTp = UtilTime::parse(UtilSystem::getEnvAsString("HISTORICAL_MARKET_DATA_START_DATE"), "%F"); + eventHandler.historicalMarketDataStartDateTp = UtilTime::parse(UtilSystem::getEnvAsString("HISTORICAL_MARKET_DATA_START_DATE")); if (startTimeStr.empty()) { eventHandler.startTimeTp = eventHandler.historicalMarketDataStartDateTp; } - eventHandler.historicalMarketDataEndDateTp = UtilTime::parse(UtilSystem::getEnvAsString("HISTORICAL_MARKET_DATA_END_DATE"), "%F"); + eventHandler.historicalMarketDataEndDateTp = UtilTime::parse(UtilSystem::getEnvAsString("HISTORICAL_MARKET_DATA_END_DATE")); if (totalDurationSecondsStr.empty()) { eventHandler.totalDurationSeconds = std::chrono::duration_cast(eventHandler.historicalMarketDataEndDateTp - eventHandler.historicalMarketDataStartDateTp).count(); diff --git a/app/src/spot_market_making/main.cpp b/app/src/spot_market_making/main.cpp index 4f2948d6..6f556444 100644 --- a/app/src/spot_market_making/main.cpp +++ b/app/src/spot_market_making/main.cpp @@ -147,11 +147,11 @@ int main(int argc, char** argv) { eventHandler.marketImpfactFactor = UtilSystem::getEnvAsDouble("MARKET_IMPACT_FACTOR"); } if (eventHandler.tradingMode == EventHandlerBase::TradingMode::BACKTEST) { - eventHandler.historicalMarketDataStartDateTp = UtilTime::parse(UtilSystem::getEnvAsString("HISTORICAL_MARKET_DATA_START_DATE"), "%F"); + eventHandler.historicalMarketDataStartDateTp = UtilTime::parse(UtilSystem::getEnvAsString("HISTORICAL_MARKET_DATA_START_DATE")); if (startTimeStr.empty()) { eventHandler.startTimeTp = eventHandler.historicalMarketDataStartDateTp; } - eventHandler.historicalMarketDataEndDateTp = UtilTime::parse(UtilSystem::getEnvAsString("HISTORICAL_MARKET_DATA_END_DATE"), "%F"); + eventHandler.historicalMarketDataEndDateTp = UtilTime::parse(UtilSystem::getEnvAsString("HISTORICAL_MARKET_DATA_END_DATE")); if (totalDurationSecondsStr.empty()) { eventHandler.totalDurationSeconds = std::chrono::duration_cast(eventHandler.historicalMarketDataEndDateTp - eventHandler.historicalMarketDataStartDateTp).count(); diff --git a/binding/CMakeLists.txt b/binding/CMakeLists.txt index f3744501..d5ed63f6 100644 --- a/binding/CMakeLists.txt +++ b/binding/CMakeLists.txt @@ -105,5 +105,5 @@ include(UseSWIG) if(BUILD_TEST) include(CTest) endif() -add_compile_options(-Wno-deprecated) +add_compile_options(-Wno-deprecated -Wno-nonnull -Wno-deprecated-declarations) add_subdirectory(python) diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index a5ac106c..63b3d86a 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -31,7 +31,7 @@ if (WIN32) set(ADDITIONAL_LINK_LIBRARIES ws2_32) endif() link_libraries(OpenSSL::Crypto OpenSSL::SSL ${ADDITIONAL_LINK_LIBRARIES}) -add_compile_options(-Wno-deprecated) +add_compile_options(-Wno-deprecated -Wno-nonnull -Wno-deprecated-declarations) add_subdirectory(src/market_data_simple_request) add_subdirectory(src/market_data_simple_subscription) add_subdirectory(src/market_data_advanced_request) diff --git a/include/ccapi_cpp/ccapi_date.h b/include/ccapi_cpp/ccapi_date.h deleted file mode 100644 index cbe21407..00000000 --- a/include/ccapi_cpp/ccapi_date.h +++ /dev/null @@ -1,5580 +0,0 @@ -#ifndef INCLUDE_CCAPI_CPP_CCAPI_DATE_H_ -#define INCLUDE_CCAPI_CPP_CCAPI_DATE_H_ -// https://github.com/HowardHinnant/date/releases/tag/v3.0.0 - -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016, 2017 Howard Hinnant -// Copyright (c) 2016 Adrian Colomitchi -// Copyright (c) 2017 Florian Dang -// Copyright (c) 2017 Paul Thompson -// Copyright (c) 2018, 2019 Tomasz KamiƄski -// Copyright (c) 2019 Jiangang Zhuang -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// Our apologies. When the previous paragraph was written, lowercase had not yet -// been invented (that would involve another several millennia of evolution). -// We did not mean to shout. - -#ifndef HAS_STRING_VIEW -#if __cplusplus >= 201703 || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) -#define HAS_STRING_VIEW 1 -#else -#define HAS_STRING_VIEW 0 -#endif -#endif // HAS_STRING_VIEW - -#include -#include -#include -#include -#include -#if !(__cplusplus >= 201402) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if HAS_STRING_VIEW -#include -#endif -#include -#include - -#ifdef __GNUC__ -#pragma GCC diagnostic push -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 7) -#pragma GCC diagnostic ignored "-Wpedantic" -#endif -#if __GNUC__ < 5 -// GCC 4.9 Bug 61489 Wrong warning with -Wmissing-field-initializers -#pragma GCC diagnostic ignored "-Wmissing-field-initializers" -#endif -#endif - -#ifdef _MSC_VER -#pragma warning(push) -// warning C4127: conditional expression is constant -#pragma warning(disable : 4127) -#endif - -namespace date { - -//---------------+ -// Configuration | -//---------------+ - -#ifndef ONLY_C_LOCALE -#define ONLY_C_LOCALE 0 -#endif - -#if defined(_MSC_VER) && (!defined(__clang__) || (_MSC_VER < 1910)) -// MSVC -#ifndef _SILENCE_CXX17_UNCAUGHT_EXCEPTION_DEPRECATION_WARNING -#define _SILENCE_CXX17_UNCAUGHT_EXCEPTION_DEPRECATION_WARNING -#endif -#if _MSC_VER < 1910 -// before VS2017 -#define CONSTDATA const -#define CONSTCD11 -#define CONSTCD14 -#define NOEXCEPT _NOEXCEPT -#else -// VS2017 and later -#define CONSTDATA constexpr const -#define CONSTCD11 constexpr -#define CONSTCD14 constexpr -#define NOEXCEPT noexcept -#endif - -#elif defined(__SUNPRO_CC) && __SUNPRO_CC <= 0x5150 -// Oracle Developer Studio 12.6 and earlier -#define CONSTDATA constexpr const -#define CONSTCD11 constexpr -#define CONSTCD14 -#define NOEXCEPT noexcept - -#elif __cplusplus >= 201402 -// C++14 -#define CONSTDATA constexpr const -#define CONSTCD11 constexpr -#define CONSTCD14 constexpr -#define NOEXCEPT noexcept -#else -// C++11 -#define CONSTDATA constexpr const -#define CONSTCD11 constexpr -#define CONSTCD14 -#define NOEXCEPT noexcept -#endif - -#ifndef HAS_UNCAUGHT_EXCEPTIONS -#if __cplusplus > 201703 || (defined(_MSVC_LANG) && _MSVC_LANG > 201703L) -#define HAS_UNCAUGHT_EXCEPTIONS 1 -#else -#define HAS_UNCAUGHT_EXCEPTIONS 0 -#endif -#endif // HAS_UNCAUGHT_EXCEPTIONS - -#ifndef HAS_VOID_T -#if __cplusplus >= 201703 || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) -#define HAS_VOID_T 1 -#else -#define HAS_VOID_T 0 -#endif -#endif // HAS_VOID_T - -// Protect from Oracle sun macro -#ifdef sun -#undef sun -#endif - -// Work around for a NVCC compiler bug which causes it to fail -// to compile std::ratio_{multiply,divide} when used directly -// in the std::chrono::duration template instantiations below -namespace detail { -template -using ratio_multiply = decltype(std::ratio_multiply{}); - -template -using ratio_divide = decltype(std::ratio_divide{}); -} // namespace detail - -//-----------+ -// Interface | -//-----------+ - -// durations - -using days = std::chrono::duration, std::chrono::hours::period>>; - -using weeks = std::chrono::duration, days::period>>; - -using years = std::chrono::duration, days::period>>; - -using months = std::chrono::duration>>; - -// time_point - -template -using sys_time = std::chrono::time_point; - -using sys_days = sys_time; -using sys_seconds = sys_time; - -struct local_t {}; - -template -using local_time = std::chrono::time_point; - -using local_seconds = local_time; -using local_days = local_time; - -// types - -struct last_spec { - explicit last_spec() = default; -}; - -class day; -class month; -class year; - -class weekday; -class weekday_indexed; -class weekday_last; - -class month_day; -class month_day_last; -class month_weekday; -class month_weekday_last; - -class year_month; - -class year_month_day; -class year_month_day_last; -class year_month_weekday; -class year_month_weekday_last; - -// date composition operators - -CONSTCD11 year_month operator/(const year& y, const month& m) NOEXCEPT; -CONSTCD11 year_month operator/(const year& y, int m) NOEXCEPT; - -CONSTCD11 month_day operator/(const day& d, const month& m) NOEXCEPT; -CONSTCD11 month_day operator/(const day& d, int m) NOEXCEPT; -CONSTCD11 month_day operator/(const month& m, const day& d) NOEXCEPT; -CONSTCD11 month_day operator/(const month& m, int d) NOEXCEPT; -CONSTCD11 month_day operator/(int m, const day& d) NOEXCEPT; - -CONSTCD11 month_day_last operator/(const month& m, last_spec) NOEXCEPT; -CONSTCD11 month_day_last operator/(int m, last_spec) NOEXCEPT; -CONSTCD11 month_day_last operator/(last_spec, const month& m) NOEXCEPT; -CONSTCD11 month_day_last operator/(last_spec, int m) NOEXCEPT; - -CONSTCD11 month_weekday operator/(const month& m, const weekday_indexed& wdi) NOEXCEPT; -CONSTCD11 month_weekday operator/(int m, const weekday_indexed& wdi) NOEXCEPT; -CONSTCD11 month_weekday operator/(const weekday_indexed& wdi, const month& m) NOEXCEPT; -CONSTCD11 month_weekday operator/(const weekday_indexed& wdi, int m) NOEXCEPT; - -CONSTCD11 month_weekday_last operator/(const month& m, const weekday_last& wdl) NOEXCEPT; -CONSTCD11 month_weekday_last operator/(int m, const weekday_last& wdl) NOEXCEPT; -CONSTCD11 month_weekday_last operator/(const weekday_last& wdl, const month& m) NOEXCEPT; -CONSTCD11 month_weekday_last operator/(const weekday_last& wdl, int m) NOEXCEPT; - -CONSTCD11 year_month_day operator/(const year_month& ym, const day& d) NOEXCEPT; -CONSTCD11 year_month_day operator/(const year_month& ym, int d) NOEXCEPT; -CONSTCD11 year_month_day operator/(const year& y, const month_day& md) NOEXCEPT; -CONSTCD11 year_month_day operator/(int y, const month_day& md) NOEXCEPT; -CONSTCD11 year_month_day operator/(const month_day& md, const year& y) NOEXCEPT; -CONSTCD11 year_month_day operator/(const month_day& md, int y) NOEXCEPT; - -CONSTCD11 -year_month_day_last operator/(const year_month& ym, last_spec) NOEXCEPT; -CONSTCD11 -year_month_day_last operator/(const year& y, const month_day_last& mdl) NOEXCEPT; -CONSTCD11 -year_month_day_last operator/(int y, const month_day_last& mdl) NOEXCEPT; -CONSTCD11 -year_month_day_last operator/(const month_day_last& mdl, const year& y) NOEXCEPT; -CONSTCD11 -year_month_day_last operator/(const month_day_last& mdl, int y) NOEXCEPT; - -CONSTCD11 -year_month_weekday operator/(const year_month& ym, const weekday_indexed& wdi) NOEXCEPT; - -CONSTCD11 -year_month_weekday operator/(const year& y, const month_weekday& mwd) NOEXCEPT; - -CONSTCD11 -year_month_weekday operator/(int y, const month_weekday& mwd) NOEXCEPT; - -CONSTCD11 -year_month_weekday operator/(const month_weekday& mwd, const year& y) NOEXCEPT; - -CONSTCD11 -year_month_weekday operator/(const month_weekday& mwd, int y) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last operator/(const year_month& ym, const weekday_last& wdl) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last operator/(const year& y, const month_weekday_last& mwdl) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last operator/(int y, const month_weekday_last& mwdl) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last operator/(const month_weekday_last& mwdl, const year& y) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last operator/(const month_weekday_last& mwdl, int y) NOEXCEPT; - -// Detailed interface - -// day - -class day { - unsigned char d_; - - public: - day() = default; - explicit CONSTCD11 day(unsigned d) NOEXCEPT; - - CONSTCD14 day& operator++() NOEXCEPT; - CONSTCD14 day operator++(int) NOEXCEPT; - CONSTCD14 day& operator--() NOEXCEPT; - CONSTCD14 day operator--(int) NOEXCEPT; - - CONSTCD14 day& operator+=(const days& d) NOEXCEPT; - CONSTCD14 day& operator-=(const days& d) NOEXCEPT; - - CONSTCD11 explicit operator unsigned() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator!=(const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator<(const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator>(const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator<=(const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator>=(const day& x, const day& y) NOEXCEPT; - -CONSTCD11 day operator+(const day& x, const days& y) NOEXCEPT; -CONSTCD11 day operator+(const days& x, const day& y) NOEXCEPT; -CONSTCD11 day operator-(const day& x, const days& y) NOEXCEPT; -CONSTCD11 days operator-(const day& x, const day& y) NOEXCEPT; - -template -std::basic_ostream& operator<<(std::basic_ostream& os, const day& d); - -// month - -class month { - unsigned char m_; - - public: - month() = default; - explicit CONSTCD11 month(unsigned m) NOEXCEPT; - - CONSTCD14 month& operator++() NOEXCEPT; - CONSTCD14 month operator++(int) NOEXCEPT; - CONSTCD14 month& operator--() NOEXCEPT; - CONSTCD14 month operator--(int) NOEXCEPT; - - CONSTCD14 month& operator+=(const months& m) NOEXCEPT; - CONSTCD14 month& operator-=(const months& m) NOEXCEPT; - - CONSTCD11 explicit operator unsigned() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator!=(const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator<(const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator>(const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator<=(const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator>=(const month& x, const month& y) NOEXCEPT; - -CONSTCD14 month operator+(const month& x, const months& y) NOEXCEPT; -CONSTCD14 month operator+(const months& x, const month& y) NOEXCEPT; -CONSTCD14 month operator-(const month& x, const months& y) NOEXCEPT; -CONSTCD14 months operator-(const month& x, const month& y) NOEXCEPT; - -template -std::basic_ostream& operator<<(std::basic_ostream& os, const month& m); - -// year - -class year { - short y_; - - public: - year() = default; - explicit CONSTCD11 year(int y) NOEXCEPT; - - CONSTCD14 year& operator++() NOEXCEPT; - CONSTCD14 year operator++(int) NOEXCEPT; - CONSTCD14 year& operator--() NOEXCEPT; - CONSTCD14 year operator--(int) NOEXCEPT; - - CONSTCD14 year& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 year operator-() const NOEXCEPT; - CONSTCD11 year operator+() const NOEXCEPT; - - CONSTCD11 bool is_leap() const NOEXCEPT; - - CONSTCD11 explicit operator int() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; - - static CONSTCD11 year min() NOEXCEPT { return year{-32767}; } - static CONSTCD11 year max() NOEXCEPT { return year{32767}; } -}; - -CONSTCD11 bool operator==(const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator!=(const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator<(const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator>(const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator<=(const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator>=(const year& x, const year& y) NOEXCEPT; - -CONSTCD11 year operator+(const year& x, const years& y) NOEXCEPT; -CONSTCD11 year operator+(const years& x, const year& y) NOEXCEPT; -CONSTCD11 year operator-(const year& x, const years& y) NOEXCEPT; -CONSTCD11 years operator-(const year& x, const year& y) NOEXCEPT; - -template -std::basic_ostream& operator<<(std::basic_ostream& os, const year& y); - -// weekday - -class weekday { - unsigned char wd_; - - public: - weekday() = default; - explicit CONSTCD11 weekday(unsigned wd) NOEXCEPT; - CONSTCD14 weekday(const sys_days& dp) NOEXCEPT; - CONSTCD14 explicit weekday(const local_days& dp) NOEXCEPT; - - CONSTCD14 weekday& operator++() NOEXCEPT; - CONSTCD14 weekday operator++(int) NOEXCEPT; - CONSTCD14 weekday& operator--() NOEXCEPT; - CONSTCD14 weekday operator--(int) NOEXCEPT; - - CONSTCD14 weekday& operator+=(const days& d) NOEXCEPT; - CONSTCD14 weekday& operator-=(const days& d) NOEXCEPT; - - CONSTCD11 bool ok() const NOEXCEPT; - - CONSTCD11 unsigned c_encoding() const NOEXCEPT; - CONSTCD11 unsigned iso_encoding() const NOEXCEPT; - - CONSTCD11 weekday_indexed operator[](unsigned index) const NOEXCEPT; - CONSTCD11 weekday_last operator[](last_spec) const NOEXCEPT; - - private: - static CONSTCD14 unsigned char weekday_from_days(int z) NOEXCEPT; - - friend CONSTCD11 bool operator==(const weekday& x, const weekday& y) NOEXCEPT; - friend CONSTCD14 days operator-(const weekday& x, const weekday& y) NOEXCEPT; - friend CONSTCD14 weekday operator+(const weekday& x, const days& y) NOEXCEPT; - template - friend std::basic_ostream& operator<<(std::basic_ostream& os, const weekday& wd); - friend class weekday_indexed; -}; - -CONSTCD11 bool operator==(const weekday& x, const weekday& y) NOEXCEPT; -CONSTCD11 bool operator!=(const weekday& x, const weekday& y) NOEXCEPT; - -CONSTCD14 weekday operator+(const weekday& x, const days& y) NOEXCEPT; -CONSTCD14 weekday operator+(const days& x, const weekday& y) NOEXCEPT; -CONSTCD14 weekday operator-(const weekday& x, const days& y) NOEXCEPT; -CONSTCD14 days operator-(const weekday& x, const weekday& y) NOEXCEPT; - -template -std::basic_ostream& operator<<(std::basic_ostream& os, const weekday& wd); - -// weekday_indexed - -class weekday_indexed { - unsigned char wd_ : 4; - unsigned char index_ : 4; - - public: - weekday_indexed() = default; - CONSTCD11 weekday_indexed(const date::weekday& wd, unsigned index) NOEXCEPT; - - CONSTCD11 date::weekday weekday() const NOEXCEPT; - CONSTCD11 unsigned index() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT; -CONSTCD11 bool operator!=(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT; - -template -std::basic_ostream& operator<<(std::basic_ostream& os, const weekday_indexed& wdi); - -// weekday_last - -class weekday_last { - date::weekday wd_; - - public: - explicit CONSTCD11 weekday_last(const date::weekday& wd) NOEXCEPT; - - CONSTCD11 date::weekday weekday() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const weekday_last& x, const weekday_last& y) NOEXCEPT; -CONSTCD11 bool operator!=(const weekday_last& x, const weekday_last& y) NOEXCEPT; - -template -std::basic_ostream& operator<<(std::basic_ostream& os, const weekday_last& wdl); - -namespace detail { - -struct unspecified_month_disambiguator {}; - -} // namespace detail - -// year_month - -class year_month { - date::year y_; - date::month m_; - - public: - year_month() = default; - CONSTCD11 year_month(const date::year& y, const date::month& m) NOEXCEPT; - - CONSTCD11 date::year year() const NOEXCEPT; - CONSTCD11 date::month month() const NOEXCEPT; - - template - CONSTCD14 year_month& operator+=(const months& dm) NOEXCEPT; - template - CONSTCD14 year_month& operator-=(const months& dm) NOEXCEPT; - CONSTCD14 year_month& operator+=(const years& dy) NOEXCEPT; - CONSTCD14 year_month& operator-=(const years& dy) NOEXCEPT; - - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator!=(const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator<(const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator>(const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator<=(const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator>=(const year_month& x, const year_month& y) NOEXCEPT; - -template -CONSTCD14 year_month operator+(const year_month& ym, const months& dm) NOEXCEPT; -template -CONSTCD14 year_month operator+(const months& dm, const year_month& ym) NOEXCEPT; -template -CONSTCD14 year_month operator-(const year_month& ym, const months& dm) NOEXCEPT; - -CONSTCD11 months operator-(const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 year_month operator+(const year_month& ym, const years& dy) NOEXCEPT; -CONSTCD11 year_month operator+(const years& dy, const year_month& ym) NOEXCEPT; -CONSTCD11 year_month operator-(const year_month& ym, const years& dy) NOEXCEPT; - -template -std::basic_ostream& operator<<(std::basic_ostream& os, const year_month& ym); - -// month_day - -class month_day { - date::month m_; - date::day d_; - - public: - month_day() = default; - CONSTCD11 month_day(const date::month& m, const date::day& d) NOEXCEPT; - - CONSTCD11 date::month month() const NOEXCEPT; - CONSTCD11 date::day day() const NOEXCEPT; - - CONSTCD14 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator!=(const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator<(const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator>(const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator<=(const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator>=(const month_day& x, const month_day& y) NOEXCEPT; - -template -std::basic_ostream& operator<<(std::basic_ostream& os, const month_day& md); - -// month_day_last - -class month_day_last { - date::month m_; - - public: - CONSTCD11 explicit month_day_last(const date::month& m) NOEXCEPT; - - CONSTCD11 date::month month() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator!=(const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator<(const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator>(const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator<=(const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator>=(const month_day_last& x, const month_day_last& y) NOEXCEPT; - -template -std::basic_ostream& operator<<(std::basic_ostream& os, const month_day_last& mdl); - -// month_weekday - -class month_weekday { - date::month m_; - date::weekday_indexed wdi_; - - public: - CONSTCD11 month_weekday(const date::month& m, const date::weekday_indexed& wdi) NOEXCEPT; - - CONSTCD11 date::month month() const NOEXCEPT; - CONSTCD11 date::weekday_indexed weekday_indexed() const NOEXCEPT; - - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const month_weekday& x, const month_weekday& y) NOEXCEPT; -CONSTCD11 bool operator!=(const month_weekday& x, const month_weekday& y) NOEXCEPT; - -template -std::basic_ostream& operator<<(std::basic_ostream& os, const month_weekday& mwd); - -// month_weekday_last - -class month_weekday_last { - date::month m_; - date::weekday_last wdl_; - - public: - CONSTCD11 month_weekday_last(const date::month& m, const date::weekday_last& wd) NOEXCEPT; - - CONSTCD11 date::month month() const NOEXCEPT; - CONSTCD11 date::weekday_last weekday_last() const NOEXCEPT; - - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 -bool operator==(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT; -CONSTCD11 -bool operator!=(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT; - -template -std::basic_ostream& operator<<(std::basic_ostream& os, const month_weekday_last& mwdl); - -// class year_month_day - -class year_month_day { - date::year y_; - date::month m_; - date::day d_; - - public: - year_month_day() = default; - CONSTCD11 year_month_day(const date::year& y, const date::month& m, const date::day& d) NOEXCEPT; - CONSTCD14 year_month_day(const year_month_day_last& ymdl) NOEXCEPT; - - CONSTCD14 year_month_day(sys_days dp) NOEXCEPT; - CONSTCD14 explicit year_month_day(local_days dp) NOEXCEPT; - - template - CONSTCD14 year_month_day& operator+=(const months& m) NOEXCEPT; - template - CONSTCD14 year_month_day& operator-=(const months& m) NOEXCEPT; - CONSTCD14 year_month_day& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year_month_day& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 date::year year() const NOEXCEPT; - CONSTCD11 date::month month() const NOEXCEPT; - CONSTCD11 date::day day() const NOEXCEPT; - - CONSTCD14 operator sys_days() const NOEXCEPT; - CONSTCD14 explicit operator local_days() const NOEXCEPT; - CONSTCD14 bool ok() const NOEXCEPT; - - private: - static CONSTCD14 year_month_day from_days(days dp) NOEXCEPT; - CONSTCD14 days to_days() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator!=(const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator<(const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator>(const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator<=(const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator>=(const year_month_day& x, const year_month_day& y) NOEXCEPT; - -template -CONSTCD14 year_month_day operator+(const year_month_day& ymd, const months& dm) NOEXCEPT; -template -CONSTCD14 year_month_day operator+(const months& dm, const year_month_day& ymd) NOEXCEPT; -template -CONSTCD14 year_month_day operator-(const year_month_day& ymd, const months& dm) NOEXCEPT; -CONSTCD11 year_month_day operator+(const year_month_day& ymd, const years& dy) NOEXCEPT; -CONSTCD11 year_month_day operator+(const years& dy, const year_month_day& ymd) NOEXCEPT; -CONSTCD11 year_month_day operator-(const year_month_day& ymd, const years& dy) NOEXCEPT; - -template -std::basic_ostream& operator<<(std::basic_ostream& os, const year_month_day& ymd); - -// year_month_day_last - -class year_month_day_last { - date::year y_; - date::month_day_last mdl_; - - public: - CONSTCD11 year_month_day_last(const date::year& y, const date::month_day_last& mdl) NOEXCEPT; - - template - CONSTCD14 year_month_day_last& operator+=(const months& m) NOEXCEPT; - template - CONSTCD14 year_month_day_last& operator-=(const months& m) NOEXCEPT; - CONSTCD14 year_month_day_last& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year_month_day_last& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 date::year year() const NOEXCEPT; - CONSTCD11 date::month month() const NOEXCEPT; - CONSTCD11 date::month_day_last month_day_last() const NOEXCEPT; - CONSTCD14 date::day day() const NOEXCEPT; - - CONSTCD14 operator sys_days() const NOEXCEPT; - CONSTCD14 explicit operator local_days() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 -bool operator==(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 -bool operator!=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 -bool operator<(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 -bool operator>(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 -bool operator<=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 -bool operator>=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; - -template -CONSTCD14 year_month_day_last operator+(const year_month_day_last& ymdl, const months& dm) NOEXCEPT; - -template -CONSTCD14 year_month_day_last operator+(const months& dm, const year_month_day_last& ymdl) NOEXCEPT; - -CONSTCD11 -year_month_day_last operator+(const year_month_day_last& ymdl, const years& dy) NOEXCEPT; - -CONSTCD11 -year_month_day_last operator+(const years& dy, const year_month_day_last& ymdl) NOEXCEPT; - -template -CONSTCD14 year_month_day_last operator-(const year_month_day_last& ymdl, const months& dm) NOEXCEPT; - -CONSTCD11 -year_month_day_last operator-(const year_month_day_last& ymdl, const years& dy) NOEXCEPT; - -template -std::basic_ostream& operator<<(std::basic_ostream& os, const year_month_day_last& ymdl); - -// year_month_weekday - -class year_month_weekday { - date::year y_; - date::month m_; - date::weekday_indexed wdi_; - - public: - year_month_weekday() = default; - CONSTCD11 year_month_weekday(const date::year& y, const date::month& m, const date::weekday_indexed& wdi) NOEXCEPT; - CONSTCD14 year_month_weekday(const sys_days& dp) NOEXCEPT; - CONSTCD14 explicit year_month_weekday(const local_days& dp) NOEXCEPT; - - template - CONSTCD14 year_month_weekday& operator+=(const months& m) NOEXCEPT; - template - CONSTCD14 year_month_weekday& operator-=(const months& m) NOEXCEPT; - CONSTCD14 year_month_weekday& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year_month_weekday& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 date::year year() const NOEXCEPT; - CONSTCD11 date::month month() const NOEXCEPT; - CONSTCD11 date::weekday weekday() const NOEXCEPT; - CONSTCD11 unsigned index() const NOEXCEPT; - CONSTCD11 date::weekday_indexed weekday_indexed() const NOEXCEPT; - - CONSTCD14 operator sys_days() const NOEXCEPT; - CONSTCD14 explicit operator local_days() const NOEXCEPT; - CONSTCD14 bool ok() const NOEXCEPT; - - private: - static CONSTCD14 year_month_weekday from_days(days dp) NOEXCEPT; - CONSTCD14 days to_days() const NOEXCEPT; -}; - -CONSTCD11 -bool operator==(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT; -CONSTCD11 -bool operator!=(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT; - -template -CONSTCD14 year_month_weekday operator+(const year_month_weekday& ymwd, const months& dm) NOEXCEPT; - -template -CONSTCD14 year_month_weekday operator+(const months& dm, const year_month_weekday& ymwd) NOEXCEPT; - -CONSTCD11 -year_month_weekday operator+(const year_month_weekday& ymwd, const years& dy) NOEXCEPT; - -CONSTCD11 -year_month_weekday operator+(const years& dy, const year_month_weekday& ymwd) NOEXCEPT; - -template -CONSTCD14 year_month_weekday operator-(const year_month_weekday& ymwd, const months& dm) NOEXCEPT; - -CONSTCD11 -year_month_weekday operator-(const year_month_weekday& ymwd, const years& dy) NOEXCEPT; - -template -std::basic_ostream& operator<<(std::basic_ostream& os, const year_month_weekday& ymwdi); - -// year_month_weekday_last - -class year_month_weekday_last { - date::year y_; - date::month m_; - date::weekday_last wdl_; - - public: - CONSTCD11 year_month_weekday_last(const date::year& y, const date::month& m, const date::weekday_last& wdl) NOEXCEPT; - - template - CONSTCD14 year_month_weekday_last& operator+=(const months& m) NOEXCEPT; - template - CONSTCD14 year_month_weekday_last& operator-=(const months& m) NOEXCEPT; - CONSTCD14 year_month_weekday_last& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year_month_weekday_last& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 date::year year() const NOEXCEPT; - CONSTCD11 date::month month() const NOEXCEPT; - CONSTCD11 date::weekday weekday() const NOEXCEPT; - CONSTCD11 date::weekday_last weekday_last() const NOEXCEPT; - - CONSTCD14 operator sys_days() const NOEXCEPT; - CONSTCD14 explicit operator local_days() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; - - private: - CONSTCD14 days to_days() const NOEXCEPT; -}; - -CONSTCD11 -bool operator==(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT; - -CONSTCD11 -bool operator!=(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT; - -template -CONSTCD14 year_month_weekday_last operator+(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT; - -template -CONSTCD14 year_month_weekday_last operator+(const months& dm, const year_month_weekday_last& ymwdl) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last operator+(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last operator+(const years& dy, const year_month_weekday_last& ymwdl) NOEXCEPT; - -template -CONSTCD14 year_month_weekday_last operator-(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last operator-(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT; - -template -std::basic_ostream& operator<<(std::basic_ostream& os, const year_month_weekday_last& ymwdl); - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) -inline namespace literals { - -CONSTCD11 date::day operator"" _d(unsigned long long d) NOEXCEPT; -CONSTCD11 date::year operator"" _y(unsigned long long y) NOEXCEPT; - -} // namespace literals -#endif // !defined(_MSC_VER) || (_MSC_VER >= 1900) - -// CONSTDATA date::month January{1}; -// CONSTDATA date::month February{2}; -// CONSTDATA date::month March{3}; -// CONSTDATA date::month April{4}; -// CONSTDATA date::month May{5}; -// CONSTDATA date::month June{6}; -// CONSTDATA date::month July{7}; -// CONSTDATA date::month August{8}; -// CONSTDATA date::month September{9}; -// CONSTDATA date::month October{10}; -// CONSTDATA date::month November{11}; -// CONSTDATA date::month December{12}; -// -// CONSTDATA date::weekday Sunday{0u}; -// CONSTDATA date::weekday Monday{1u}; -// CONSTDATA date::weekday Tuesday{2u}; -// CONSTDATA date::weekday Wednesday{3u}; -// CONSTDATA date::weekday Thursday{4u}; -// CONSTDATA date::weekday Friday{5u}; -// CONSTDATA date::weekday Saturday{6u}; - -#if HAS_VOID_T - -template > -struct is_clock : std::false_type {}; - -template -struct is_clock> - : std::true_type {}; - -#endif // HAS_VOID_T - -//----------------+ -// Implementation | -//----------------+ - -// utilities -namespace detail { - -template > -class save_istream { - protected: - std::basic_ios& is_; - CharT fill_; - std::ios::fmtflags flags_; - std::streamsize width_; - std::basic_ostream* tie_; - std::locale loc_; - - public: - ~save_istream() { - is_.fill(fill_); - is_.flags(flags_); - is_.width(width_); - is_.imbue(loc_); - is_.tie(tie_); - } - - save_istream(const save_istream&) = delete; - save_istream& operator=(const save_istream&) = delete; - - explicit save_istream(std::basic_ios& is) - : is_(is), fill_(is.fill()), flags_(is.flags()), width_(is.width(0)), tie_(is.tie(nullptr)), loc_(is.getloc()) { - if (tie_ != nullptr) tie_->flush(); - } -}; - -template > -class save_ostream : private save_istream { - public: - ~save_ostream() { - if ((this->flags_ & std::ios::unitbuf) && -#if HAS_UNCAUGHT_EXCEPTIONS - std::uncaught_exceptions() == 0 && -#else - !std::uncaught_exception() && -#endif - this->is_.good()) - this->is_.rdbuf()->pubsync(); - } - - save_ostream(const save_ostream&) = delete; - save_ostream& operator=(const save_ostream&) = delete; - - explicit save_ostream(std::basic_ios& os) : save_istream(os) {} -}; - -template -struct choose_trunc_type { - static const int digits = std::numeric_limits::digits; - using type = typename std::conditional < digits < 32, std::int32_t, - typename std::conditional::type>::type; -}; - -template -CONSTCD11 inline typename std::enable_if::value, T>::type trunc(T t) NOEXCEPT { - return t; -} - -template -CONSTCD14 inline typename std::enable_if::value, T>::type trunc(T t) NOEXCEPT { - using std::numeric_limits; - using I = typename choose_trunc_type::type; - CONSTDATA auto digits = numeric_limits::digits; - static_assert(digits < numeric_limits::digits, ""); - CONSTDATA auto max = I{1} << (digits - 1); - CONSTDATA auto min = -max; - const auto negative = t < T{0}; - if (min <= t && t <= max && t != 0 && t == t) { - t = static_cast(static_cast(t)); - if (t == 0 && negative) t = -t; - } - return t; -} - -template -struct static_gcd { - static const std::intmax_t value = static_gcd::value; -}; - -template -struct static_gcd { - static const std::intmax_t value = Xp; -}; - -template <> -struct static_gcd<0, 0> { - static const std::intmax_t value = 1; -}; - -template -struct no_overflow { - private: - static const std::intmax_t gcd_n1_n2 = static_gcd::value; - static const std::intmax_t gcd_d1_d2 = static_gcd::value; - static const std::intmax_t n1 = R1::num / gcd_n1_n2; - static const std::intmax_t d1 = R1::den / gcd_d1_d2; - static const std::intmax_t n2 = R2::num / gcd_n1_n2; - static const std::intmax_t d2 = R2::den / gcd_d1_d2; - static const std::intmax_t max = std::numeric_limits::max(); - - template - struct mul // overflow == false - { - static const std::intmax_t value = Xp * Yp; - }; - - template - struct mul { - static const std::intmax_t value = 1; - }; - - public: - static const bool value = (n1 <= max / d2) && (n2 <= max / d1); - typedef std::ratio::value, mul::value> type; -}; - -} // namespace detail - -// trunc towards zero -template -CONSTCD11 inline typename std::enable_if::value, To>::type trunc(const std::chrono::duration& d) { - return To{detail::trunc(std::chrono::duration_cast(d).count())}; -} - -template -CONSTCD11 inline typename std::enable_if::value, To>::type trunc( - const std::chrono::duration& d) { - using std::chrono::duration; - using std::chrono::duration_cast; - using rep = typename std::common_type::type; - return To{detail::trunc(duration_cast(duration_cast>(d)).count())}; -} - -#ifndef HAS_CHRONO_ROUNDING -#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 190023918 || (_MSC_FULL_VER >= 190000000 && defined(__clang__))) -#define HAS_CHRONO_ROUNDING 1 -#elif defined(__cpp_lib_chrono) && __cplusplus > 201402 && __cpp_lib_chrono >= 201510 -#define HAS_CHRONO_ROUNDING 1 -#elif defined(_LIBCPP_VERSION) && __cplusplus > 201402 && _LIBCPP_VERSION >= 3800 -#define HAS_CHRONO_ROUNDING 1 -#else -#define HAS_CHRONO_ROUNDING 0 -#endif -#endif // HAS_CHRONO_ROUNDING - -#if HAS_CHRONO_ROUNDING == 0 - -// round down -template -CONSTCD14 inline typename std::enable_if::value, To>::type floor(const std::chrono::duration& d) { - auto t = trunc(d); - if (t > d) return t - To{1}; - return t; -} - -template -CONSTCD14 inline typename std::enable_if::value, To>::type floor( - const std::chrono::duration& d) { - using rep = typename std::common_type::type; - return floor(floor>(d)); -} - -// round to nearest, to even on tie -template -CONSTCD14 inline To round(const std::chrono::duration& d) { - auto t0 = floor(d); - auto t1 = t0 + To{1}; - if (t1 == To{0} && t0 < To{0}) t1 = -t1; - auto diff0 = d - t0; - auto diff1 = t1 - d; - if (diff0 == diff1) { - if (t0 - trunc(t0 / 2) * 2 == To{0}) return t0; - return t1; - } - if (diff0 < diff1) return t0; - return t1; -} - -// round up -template -CONSTCD14 inline To ceil(const std::chrono::duration& d) { - auto t = trunc(d); - if (t < d) return t + To{1}; - return t; -} - -template ::is_signed>::type> -CONSTCD11 std::chrono::duration abs(std::chrono::duration d) { - return d >= d.zero() ? d : -d; -} - -// round down -template -CONSTCD11 inline std::chrono::time_point floor(const std::chrono::time_point& tp) { - using std::chrono::time_point; - return time_point{date::floor(tp.time_since_epoch())}; -} - -// round to nearest, to even on tie -template -CONSTCD11 inline std::chrono::time_point round(const std::chrono::time_point& tp) { - using std::chrono::time_point; - return time_point{round(tp.time_since_epoch())}; -} - -// round up -template -CONSTCD11 inline std::chrono::time_point ceil(const std::chrono::time_point& tp) { - using std::chrono::time_point; - return time_point{ceil(tp.time_since_epoch())}; -} - -#else // HAS_CHRONO_ROUNDING == 1 - -using std::chrono::abs; -using std::chrono::ceil; -using std::chrono::floor; -using std::chrono::round; - -#endif // HAS_CHRONO_ROUNDING - -// trunc towards zero -template -CONSTCD11 inline std::chrono::time_point trunc(const std::chrono::time_point& tp) { - using std::chrono::time_point; - return time_point{trunc(tp.time_since_epoch())}; -} - -// day - -CONSTCD11 inline day::day(unsigned d) NOEXCEPT : d_(static_cast(d)) {} -CONSTCD14 inline day& day::operator++() NOEXCEPT { - ++d_; - return *this; -} -CONSTCD14 inline day day::operator++(int) NOEXCEPT { - auto tmp(*this); - ++(*this); - return tmp; -} -CONSTCD14 inline day& day::operator--() NOEXCEPT { - --d_; - return *this; -} -CONSTCD14 inline day day::operator--(int) NOEXCEPT { - auto tmp(*this); - --(*this); - return tmp; -} -CONSTCD14 inline day& day::operator+=(const days& d) NOEXCEPT { - *this = *this + d; - return *this; -} -CONSTCD14 inline day& day::operator-=(const days& d) NOEXCEPT { - *this = *this - d; - return *this; -} -CONSTCD11 inline day::operator unsigned() const NOEXCEPT { return d_; } -CONSTCD11 inline bool day::ok() const NOEXCEPT { return 1 <= d_ && d_ <= 31; } - -CONSTCD11 -inline bool operator==(const day& x, const day& y) NOEXCEPT { return static_cast(x) == static_cast(y); } - -CONSTCD11 -inline bool operator!=(const day& x, const day& y) NOEXCEPT { return !(x == y); } - -CONSTCD11 -inline bool operator<(const day& x, const day& y) NOEXCEPT { return static_cast(x) < static_cast(y); } - -CONSTCD11 -inline bool operator>(const day& x, const day& y) NOEXCEPT { return y < x; } - -CONSTCD11 -inline bool operator<=(const day& x, const day& y) NOEXCEPT { return !(y < x); } - -CONSTCD11 -inline bool operator>=(const day& x, const day& y) NOEXCEPT { return !(x < y); } - -CONSTCD11 -inline days operator-(const day& x, const day& y) NOEXCEPT { return days{static_cast(static_cast(x) - static_cast(y))}; } - -CONSTCD11 -inline day operator+(const day& x, const days& y) NOEXCEPT { return day{static_cast(x) + static_cast(y.count())}; } - -CONSTCD11 -inline day operator+(const days& x, const day& y) NOEXCEPT { return y + x; } - -CONSTCD11 -inline day operator-(const day& x, const days& y) NOEXCEPT { return x + -y; } - -template -inline std::basic_ostream& operator<<(std::basic_ostream& os, const day& d) { - detail::save_ostream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(2); - os << static_cast(d); - if (!d.ok()) os << " is not a valid day"; - return os; -} - -// month - -CONSTCD11 inline month::month(unsigned m) NOEXCEPT : m_(static_cast(m)) {} -CONSTCD14 inline month& month::operator++() NOEXCEPT { - *this += months{1}; - return *this; -} -CONSTCD14 inline month month::operator++(int) NOEXCEPT { - auto tmp(*this); - ++(*this); - return tmp; -} -CONSTCD14 inline month& month::operator--() NOEXCEPT { - *this -= months{1}; - return *this; -} -CONSTCD14 inline month month::operator--(int) NOEXCEPT { - auto tmp(*this); - --(*this); - return tmp; -} - -CONSTCD14 -inline month& month::operator+=(const months& m) NOEXCEPT { - *this = *this + m; - return *this; -} - -CONSTCD14 -inline month& month::operator-=(const months& m) NOEXCEPT { - *this = *this - m; - return *this; -} - -CONSTCD11 inline month::operator unsigned() const NOEXCEPT { return m_; } -CONSTCD11 inline bool month::ok() const NOEXCEPT { return 1 <= m_ && m_ <= 12; } - -CONSTCD11 -inline bool operator==(const month& x, const month& y) NOEXCEPT { return static_cast(x) == static_cast(y); } - -CONSTCD11 -inline bool operator!=(const month& x, const month& y) NOEXCEPT { return !(x == y); } - -CONSTCD11 -inline bool operator<(const month& x, const month& y) NOEXCEPT { return static_cast(x) < static_cast(y); } - -CONSTCD11 -inline bool operator>(const month& x, const month& y) NOEXCEPT { return y < x; } - -CONSTCD11 -inline bool operator<=(const month& x, const month& y) NOEXCEPT { return !(y < x); } - -CONSTCD11 -inline bool operator>=(const month& x, const month& y) NOEXCEPT { return !(x < y); } - -CONSTCD14 -inline months operator-(const month& x, const month& y) NOEXCEPT { - auto const d = static_cast(x) - static_cast(y); - return months(d <= 11 ? d : d + 12); -} - -CONSTCD14 -inline month operator+(const month& x, const months& y) NOEXCEPT { - auto const mu = static_cast(static_cast(x)) + y.count() - 1; - auto const yr = (mu >= 0 ? mu : mu - 11) / 12; - return month{static_cast(mu - yr * 12 + 1)}; -} - -CONSTCD14 -inline month operator+(const months& x, const month& y) NOEXCEPT { return y + x; } - -CONSTCD14 -inline month operator-(const month& x, const months& y) NOEXCEPT { return x + -y; } - -template -inline std::basic_ostream& operator<<(std::basic_ostream& os, const month& m) { - if (m.ok()) { - CharT fmt[] = {'%', 'b', 0}; - os << format(os.getloc(), fmt, m); - } else - os << static_cast(m) << " is not a valid month"; - return os; -} - -// year - -CONSTCD11 inline year::year(int y) NOEXCEPT : y_(static_cast(y)) {} -CONSTCD14 inline year& year::operator++() NOEXCEPT { - ++y_; - return *this; -} -CONSTCD14 inline year year::operator++(int) NOEXCEPT { - auto tmp(*this); - ++(*this); - return tmp; -} -CONSTCD14 inline year& year::operator--() NOEXCEPT { - --y_; - return *this; -} -CONSTCD14 inline year year::operator--(int) NOEXCEPT { - auto tmp(*this); - --(*this); - return tmp; -} -CONSTCD14 inline year& year::operator+=(const years& y) NOEXCEPT { - *this = *this + y; - return *this; -} -CONSTCD14 inline year& year::operator-=(const years& y) NOEXCEPT { - *this = *this - y; - return *this; -} -CONSTCD11 inline year year::operator-() const NOEXCEPT { return year{-y_}; } -CONSTCD11 inline year year::operator+() const NOEXCEPT { return *this; } - -CONSTCD11 -inline bool year::is_leap() const NOEXCEPT { return y_ % 4 == 0 && (y_ % 100 != 0 || y_ % 400 == 0); } - -CONSTCD11 inline year::operator int() const NOEXCEPT { return y_; } - -CONSTCD11 -inline bool year::ok() const NOEXCEPT { return y_ != std::numeric_limits::min(); } - -CONSTCD11 -inline bool operator==(const year& x, const year& y) NOEXCEPT { return static_cast(x) == static_cast(y); } - -CONSTCD11 -inline bool operator!=(const year& x, const year& y) NOEXCEPT { return !(x == y); } - -CONSTCD11 -inline bool operator<(const year& x, const year& y) NOEXCEPT { return static_cast(x) < static_cast(y); } - -CONSTCD11 -inline bool operator>(const year& x, const year& y) NOEXCEPT { return y < x; } - -CONSTCD11 -inline bool operator<=(const year& x, const year& y) NOEXCEPT { return !(y < x); } - -CONSTCD11 -inline bool operator>=(const year& x, const year& y) NOEXCEPT { return !(x < y); } - -CONSTCD11 -inline years operator-(const year& x, const year& y) NOEXCEPT { return years{static_cast(x) - static_cast(y)}; } - -CONSTCD11 -inline year operator+(const year& x, const years& y) NOEXCEPT { return year{static_cast(x) + y.count()}; } - -CONSTCD11 -inline year operator+(const years& x, const year& y) NOEXCEPT { return y + x; } - -CONSTCD11 -inline year operator-(const year& x, const years& y) NOEXCEPT { return year{static_cast(x) - y.count()}; } - -template -inline std::basic_ostream& operator<<(std::basic_ostream& os, const year& y) { - detail::save_ostream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::internal); - os.width(4 + (y < year{0})); - os.imbue(std::locale::classic()); - os << static_cast(y); - if (!y.ok()) os << " is not a valid year"; - return os; -} - -// weekday - -CONSTCD14 -inline unsigned char weekday::weekday_from_days(int z) NOEXCEPT { - auto u = static_cast(z); - return static_cast(z >= -4 ? (u + 4) % 7 : u % 7); -} - -CONSTCD11 -inline weekday::weekday(unsigned wd) NOEXCEPT : wd_(static_cast(wd != 7 ? wd : 0)) {} - -CONSTCD14 -inline weekday::weekday(const sys_days& dp) NOEXCEPT : wd_(weekday_from_days(dp.time_since_epoch().count())) {} - -CONSTCD14 -inline weekday::weekday(const local_days& dp) NOEXCEPT : wd_(weekday_from_days(dp.time_since_epoch().count())) {} - -CONSTCD14 inline weekday& weekday::operator++() NOEXCEPT { - *this += days{1}; - return *this; -} -CONSTCD14 inline weekday weekday::operator++(int) NOEXCEPT { - auto tmp(*this); - ++(*this); - return tmp; -} -CONSTCD14 inline weekday& weekday::operator--() NOEXCEPT { - *this -= days{1}; - return *this; -} -CONSTCD14 inline weekday weekday::operator--(int) NOEXCEPT { - auto tmp(*this); - --(*this); - return tmp; -} - -CONSTCD14 -inline weekday& weekday::operator+=(const days& d) NOEXCEPT { - *this = *this + d; - return *this; -} - -CONSTCD14 -inline weekday& weekday::operator-=(const days& d) NOEXCEPT { - *this = *this - d; - return *this; -} - -CONSTCD11 inline bool weekday::ok() const NOEXCEPT { return wd_ <= 6; } - -CONSTCD11 -inline unsigned weekday::c_encoding() const NOEXCEPT { return unsigned{wd_}; } - -CONSTCD11 -inline unsigned weekday::iso_encoding() const NOEXCEPT { return unsigned{((wd_ == 0u) ? 7u : wd_)}; } - -CONSTCD11 -inline bool operator==(const weekday& x, const weekday& y) NOEXCEPT { return x.wd_ == y.wd_; } - -CONSTCD11 -inline bool operator!=(const weekday& x, const weekday& y) NOEXCEPT { return !(x == y); } - -CONSTCD14 -inline days operator-(const weekday& x, const weekday& y) NOEXCEPT { - auto const wdu = x.wd_ - y.wd_; - auto const wk = (wdu >= 0 ? wdu : wdu - 6) / 7; - return days{wdu - wk * 7}; -} - -CONSTCD14 -inline weekday operator+(const weekday& x, const days& y) NOEXCEPT { - auto const wdu = static_cast(static_cast(x.wd_)) + y.count(); - auto const wk = (wdu >= 0 ? wdu : wdu - 6) / 7; - return weekday{static_cast(wdu - wk * 7)}; -} - -CONSTCD14 -inline weekday operator+(const days& x, const weekday& y) NOEXCEPT { return y + x; } - -CONSTCD14 -inline weekday operator-(const weekday& x, const days& y) NOEXCEPT { return x + -y; } - -template -inline std::basic_ostream& operator<<(std::basic_ostream& os, const weekday& wd) { - if (wd.ok()) { - CharT fmt[] = {'%', 'a', 0}; - os << format(fmt, wd); - } else - os << static_cast(wd.wd_) << " is not a valid weekday"; - return os; -} - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) -inline namespace literals { - -CONSTCD11 -inline date::day operator"" _d(unsigned long long d) NOEXCEPT { return date::day{static_cast(d)}; } - -CONSTCD11 -inline date::year operator"" _y(unsigned long long y) NOEXCEPT { return date::year(static_cast(y)); } -#endif // !defined(_MSC_VER) || (_MSC_VER >= 1900) - -CONSTDATA date::last_spec last{}; - -CONSTDATA date::month jan{1}; -CONSTDATA date::month feb{2}; -CONSTDATA date::month mar{3}; -CONSTDATA date::month apr{4}; -CONSTDATA date::month may{5}; -CONSTDATA date::month jun{6}; -CONSTDATA date::month jul{7}; -CONSTDATA date::month aug{8}; -CONSTDATA date::month sep{9}; -CONSTDATA date::month oct{10}; -CONSTDATA date::month nov{11}; -CONSTDATA date::month dec{12}; - -CONSTDATA date::weekday sun{0u}; -CONSTDATA date::weekday mon{1u}; -CONSTDATA date::weekday tue{2u}; -CONSTDATA date::weekday wed{3u}; -CONSTDATA date::weekday thu{4u}; -CONSTDATA date::weekday fri{5u}; -CONSTDATA date::weekday sat{6u}; - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) -} // inline namespace literals -#endif - -CONSTDATA date::month January{1}; -CONSTDATA date::month February{2}; -CONSTDATA date::month March{3}; -CONSTDATA date::month April{4}; -CONSTDATA date::month May{5}; -CONSTDATA date::month June{6}; -CONSTDATA date::month July{7}; -CONSTDATA date::month August{8}; -CONSTDATA date::month September{9}; -CONSTDATA date::month October{10}; -CONSTDATA date::month November{11}; -CONSTDATA date::month December{12}; - -CONSTDATA date::weekday Monday{1}; -CONSTDATA date::weekday Tuesday{2}; -CONSTDATA date::weekday Wednesday{3}; -CONSTDATA date::weekday Thursday{4}; -CONSTDATA date::weekday Friday{5}; -CONSTDATA date::weekday Saturday{6}; -CONSTDATA date::weekday Sunday{7}; - -// weekday_indexed - -CONSTCD11 -inline weekday weekday_indexed::weekday() const NOEXCEPT { return date::weekday{static_cast(wd_)}; } - -CONSTCD11 inline unsigned weekday_indexed::index() const NOEXCEPT { return index_; } - -CONSTCD11 -inline bool weekday_indexed::ok() const NOEXCEPT { return weekday().ok() && 1 <= index_ && index_ <= 5; } - -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#endif // __GNUC__ - -CONSTCD11 -inline weekday_indexed::weekday_indexed(const date::weekday& wd, unsigned index) NOEXCEPT : wd_(static_cast(static_cast(wd.wd_))), - index_(static_cast(index)) {} - -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif // __GNUC__ - -template -inline std::basic_ostream& operator<<(std::basic_ostream& os, const weekday_indexed& wdi) { - os << wdi.weekday() << '[' << wdi.index(); - if (!(1 <= wdi.index() && wdi.index() <= 5)) os << " is not a valid index"; - os << ']'; - return os; -} - -CONSTCD11 -inline weekday_indexed weekday::operator[](unsigned index) const NOEXCEPT { return {*this, index}; } - -CONSTCD11 -inline bool operator==(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT { return x.weekday() == y.weekday() && x.index() == y.index(); } - -CONSTCD11 -inline bool operator!=(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT { return !(x == y); } - -// weekday_last - -CONSTCD11 inline date::weekday weekday_last::weekday() const NOEXCEPT { return wd_; } -CONSTCD11 inline bool weekday_last::ok() const NOEXCEPT { return wd_.ok(); } -CONSTCD11 inline weekday_last::weekday_last(const date::weekday& wd) NOEXCEPT : wd_(wd) {} - -CONSTCD11 -inline bool operator==(const weekday_last& x, const weekday_last& y) NOEXCEPT { return x.weekday() == y.weekday(); } - -CONSTCD11 -inline bool operator!=(const weekday_last& x, const weekday_last& y) NOEXCEPT { return !(x == y); } - -template -inline std::basic_ostream& operator<<(std::basic_ostream& os, const weekday_last& wdl) { - return os << wdl.weekday() << "[last]"; -} - -CONSTCD11 -inline weekday_last weekday::operator[](last_spec) const NOEXCEPT { return weekday_last{*this}; } - -// year_month - -CONSTCD11 -inline year_month::year_month(const date::year& y, const date::month& m) NOEXCEPT : y_(y), m_(m) {} - -CONSTCD11 inline year year_month::year() const NOEXCEPT { return y_; } -CONSTCD11 inline month year_month::month() const NOEXCEPT { return m_; } -CONSTCD11 inline bool year_month::ok() const NOEXCEPT { return y_.ok() && m_.ok(); } - -template -CONSTCD14 inline year_month& year_month::operator+=(const months& dm) NOEXCEPT { - *this = *this + dm; - return *this; -} - -template -CONSTCD14 inline year_month& year_month::operator-=(const months& dm) NOEXCEPT { - *this = *this - dm; - return *this; -} - -CONSTCD14 -inline year_month& year_month::operator+=(const years& dy) NOEXCEPT { - *this = *this + dy; - return *this; -} - -CONSTCD14 -inline year_month& year_month::operator-=(const years& dy) NOEXCEPT { - *this = *this - dy; - return *this; -} - -CONSTCD11 -inline bool operator==(const year_month& x, const year_month& y) NOEXCEPT { return x.year() == y.year() && x.month() == y.month(); } - -CONSTCD11 -inline bool operator!=(const year_month& x, const year_month& y) NOEXCEPT { return !(x == y); } - -CONSTCD11 -inline bool operator<(const year_month& x, const year_month& y) NOEXCEPT { - return x.year() < y.year() ? true : (x.year() > y.year() ? false : (x.month() < y.month())); -} - -CONSTCD11 -inline bool operator>(const year_month& x, const year_month& y) NOEXCEPT { return y < x; } - -CONSTCD11 -inline bool operator<=(const year_month& x, const year_month& y) NOEXCEPT { return !(y < x); } - -CONSTCD11 -inline bool operator>=(const year_month& x, const year_month& y) NOEXCEPT { return !(x < y); } - -template -CONSTCD14 inline year_month operator+(const year_month& ym, const months& dm) NOEXCEPT { - auto dmi = static_cast(static_cast(ym.month())) - 1 + dm.count(); - auto dy = (dmi >= 0 ? dmi : dmi - 11) / 12; - dmi = dmi - dy * 12 + 1; - return (ym.year() + years(dy)) / month(static_cast(dmi)); -} - -template -CONSTCD14 inline year_month operator+(const months& dm, const year_month& ym) NOEXCEPT { - return ym + dm; -} - -template -CONSTCD14 inline year_month operator-(const year_month& ym, const months& dm) NOEXCEPT { - return ym + -dm; -} - -CONSTCD11 -inline months operator-(const year_month& x, const year_month& y) NOEXCEPT { - return (x.year() - y.year()) + months(static_cast(x.month()) - static_cast(y.month())); -} - -CONSTCD11 -inline year_month operator+(const year_month& ym, const years& dy) NOEXCEPT { return (ym.year() + dy) / ym.month(); } - -CONSTCD11 -inline year_month operator+(const years& dy, const year_month& ym) NOEXCEPT { return ym + dy; } - -CONSTCD11 -inline year_month operator-(const year_month& ym, const years& dy) NOEXCEPT { return ym + -dy; } - -template -inline std::basic_ostream& operator<<(std::basic_ostream& os, const year_month& ym) { - return os << ym.year() << '/' << ym.month(); -} - -// month_day - -CONSTCD11 -inline month_day::month_day(const date::month& m, const date::day& d) NOEXCEPT : m_(m), d_(d) {} - -CONSTCD11 inline date::month month_day::month() const NOEXCEPT { return m_; } -CONSTCD11 inline date::day month_day::day() const NOEXCEPT { return d_; } - -CONSTCD14 -inline bool month_day::ok() const NOEXCEPT { - CONSTDATA date::day d[] = {date::day(31), date::day(29), date::day(31), date::day(30), date::day(31), date::day(30), - date::day(31), date::day(31), date::day(30), date::day(31), date::day(30), date::day(31)}; - return m_.ok() && date::day{1} <= d_ && d_ <= d[static_cast(m_) - 1]; -} - -CONSTCD11 -inline bool operator==(const month_day& x, const month_day& y) NOEXCEPT { return x.month() == y.month() && x.day() == y.day(); } - -CONSTCD11 -inline bool operator!=(const month_day& x, const month_day& y) NOEXCEPT { return !(x == y); } - -CONSTCD11 -inline bool operator<(const month_day& x, const month_day& y) NOEXCEPT { - return x.month() < y.month() ? true : (x.month() > y.month() ? false : (x.day() < y.day())); -} - -CONSTCD11 -inline bool operator>(const month_day& x, const month_day& y) NOEXCEPT { return y < x; } - -CONSTCD11 -inline bool operator<=(const month_day& x, const month_day& y) NOEXCEPT { return !(y < x); } - -CONSTCD11 -inline bool operator>=(const month_day& x, const month_day& y) NOEXCEPT { return !(x < y); } - -template -inline std::basic_ostream& operator<<(std::basic_ostream& os, const month_day& md) { - return os << md.month() << '/' << md.day(); -} - -// month_day_last - -CONSTCD11 inline month month_day_last::month() const NOEXCEPT { return m_; } -CONSTCD11 inline bool month_day_last::ok() const NOEXCEPT { return m_.ok(); } -CONSTCD11 inline month_day_last::month_day_last(const date::month& m) NOEXCEPT : m_(m) {} - -CONSTCD11 -inline bool operator==(const month_day_last& x, const month_day_last& y) NOEXCEPT { return x.month() == y.month(); } - -CONSTCD11 -inline bool operator!=(const month_day_last& x, const month_day_last& y) NOEXCEPT { return !(x == y); } - -CONSTCD11 -inline bool operator<(const month_day_last& x, const month_day_last& y) NOEXCEPT { return x.month() < y.month(); } - -CONSTCD11 -inline bool operator>(const month_day_last& x, const month_day_last& y) NOEXCEPT { return y < x; } - -CONSTCD11 -inline bool operator<=(const month_day_last& x, const month_day_last& y) NOEXCEPT { return !(y < x); } - -CONSTCD11 -inline bool operator>=(const month_day_last& x, const month_day_last& y) NOEXCEPT { return !(x < y); } - -template -inline std::basic_ostream& operator<<(std::basic_ostream& os, const month_day_last& mdl) { - return os << mdl.month() << "/last"; -} - -// month_weekday - -CONSTCD11 -inline month_weekday::month_weekday(const date::month& m, const date::weekday_indexed& wdi) NOEXCEPT : m_(m), wdi_(wdi) {} - -CONSTCD11 inline month month_weekday::month() const NOEXCEPT { return m_; } - -CONSTCD11 -inline weekday_indexed month_weekday::weekday_indexed() const NOEXCEPT { return wdi_; } - -CONSTCD11 -inline bool month_weekday::ok() const NOEXCEPT { return m_.ok() && wdi_.ok(); } - -CONSTCD11 -inline bool operator==(const month_weekday& x, const month_weekday& y) NOEXCEPT { return x.month() == y.month() && x.weekday_indexed() == y.weekday_indexed(); } - -CONSTCD11 -inline bool operator!=(const month_weekday& x, const month_weekday& y) NOEXCEPT { return !(x == y); } - -template -inline std::basic_ostream& operator<<(std::basic_ostream& os, const month_weekday& mwd) { - return os << mwd.month() << '/' << mwd.weekday_indexed(); -} - -// month_weekday_last - -CONSTCD11 -inline month_weekday_last::month_weekday_last(const date::month& m, const date::weekday_last& wdl) NOEXCEPT : m_(m), wdl_(wdl) {} - -CONSTCD11 inline month month_weekday_last::month() const NOEXCEPT { return m_; } - -CONSTCD11 -inline weekday_last month_weekday_last::weekday_last() const NOEXCEPT { return wdl_; } - -CONSTCD11 -inline bool month_weekday_last::ok() const NOEXCEPT { return m_.ok() && wdl_.ok(); } - -CONSTCD11 -inline bool operator==(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT { - return x.month() == y.month() && x.weekday_last() == y.weekday_last(); -} - -CONSTCD11 -inline bool operator!=(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT { return !(x == y); } - -template -inline std::basic_ostream& operator<<(std::basic_ostream& os, const month_weekday_last& mwdl) { - return os << mwdl.month() << '/' << mwdl.weekday_last(); -} - -// year_month_day_last - -CONSTCD11 -inline year_month_day_last::year_month_day_last(const date::year& y, const date::month_day_last& mdl) NOEXCEPT : y_(y), mdl_(mdl) {} - -template -CONSTCD14 inline year_month_day_last& year_month_day_last::operator+=(const months& m) NOEXCEPT { - *this = *this + m; - return *this; -} - -template -CONSTCD14 inline year_month_day_last& year_month_day_last::operator-=(const months& m) NOEXCEPT { - *this = *this - m; - return *this; -} - -CONSTCD14 -inline year_month_day_last& year_month_day_last::operator+=(const years& y) NOEXCEPT { - *this = *this + y; - return *this; -} - -CONSTCD14 -inline year_month_day_last& year_month_day_last::operator-=(const years& y) NOEXCEPT { - *this = *this - y; - return *this; -} - -CONSTCD11 inline year year_month_day_last::year() const NOEXCEPT { return y_; } -CONSTCD11 inline month year_month_day_last::month() const NOEXCEPT { return mdl_.month(); } - -CONSTCD11 -inline month_day_last year_month_day_last::month_day_last() const NOEXCEPT { return mdl_; } - -CONSTCD14 -inline day year_month_day_last::day() const NOEXCEPT { - CONSTDATA date::day d[] = {date::day(31), date::day(28), date::day(31), date::day(30), date::day(31), date::day(30), - date::day(31), date::day(31), date::day(30), date::day(31), date::day(30), date::day(31)}; - return (month() != February || !y_.is_leap()) && mdl_.ok() ? d[static_cast(month()) - 1] : date::day{29}; -} - -CONSTCD14 -inline year_month_day_last::operator sys_days() const NOEXCEPT { return sys_days(year() / month() / day()); } - -CONSTCD14 -inline year_month_day_last::operator local_days() const NOEXCEPT { return local_days(year() / month() / day()); } - -CONSTCD11 -inline bool year_month_day_last::ok() const NOEXCEPT { return y_.ok() && mdl_.ok(); } - -CONSTCD11 -inline bool operator==(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT { - return x.year() == y.year() && x.month_day_last() == y.month_day_last(); -} - -CONSTCD11 -inline bool operator!=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT { return !(x == y); } - -CONSTCD11 -inline bool operator<(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT { - return x.year() < y.year() ? true : (x.year() > y.year() ? false : (x.month_day_last() < y.month_day_last())); -} - -CONSTCD11 -inline bool operator>(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT { return y < x; } - -CONSTCD11 -inline bool operator<=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT { return !(y < x); } - -CONSTCD11 -inline bool operator>=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT { return !(x < y); } - -template -inline std::basic_ostream& operator<<(std::basic_ostream& os, const year_month_day_last& ymdl) { - return os << ymdl.year() << '/' << ymdl.month_day_last(); -} - -template -CONSTCD14 inline year_month_day_last operator+(const year_month_day_last& ymdl, const months& dm) NOEXCEPT { - return (ymdl.year() / ymdl.month() + dm) / last; -} - -template -CONSTCD14 inline year_month_day_last operator+(const months& dm, const year_month_day_last& ymdl) NOEXCEPT { - return ymdl + dm; -} - -template -CONSTCD14 inline year_month_day_last operator-(const year_month_day_last& ymdl, const months& dm) NOEXCEPT { - return ymdl + (-dm); -} - -CONSTCD11 -inline year_month_day_last operator+(const year_month_day_last& ymdl, const years& dy) NOEXCEPT { return {ymdl.year() + dy, ymdl.month_day_last()}; } - -CONSTCD11 -inline year_month_day_last operator+(const years& dy, const year_month_day_last& ymdl) NOEXCEPT { return ymdl + dy; } - -CONSTCD11 -inline year_month_day_last operator-(const year_month_day_last& ymdl, const years& dy) NOEXCEPT { return ymdl + (-dy); } - -// year_month_day - -CONSTCD11 -inline year_month_day::year_month_day(const date::year& y, const date::month& m, const date::day& d) NOEXCEPT : y_(y), m_(m), d_(d) {} - -CONSTCD14 -inline year_month_day::year_month_day(const year_month_day_last& ymdl) NOEXCEPT : y_(ymdl.year()), m_(ymdl.month()), d_(ymdl.day()) {} - -CONSTCD14 -inline year_month_day::year_month_day(sys_days dp) NOEXCEPT : year_month_day(from_days(dp.time_since_epoch())) {} - -CONSTCD14 -inline year_month_day::year_month_day(local_days dp) NOEXCEPT : year_month_day(from_days(dp.time_since_epoch())) {} - -CONSTCD11 inline year year_month_day::year() const NOEXCEPT { return y_; } -CONSTCD11 inline month year_month_day::month() const NOEXCEPT { return m_; } -CONSTCD11 inline day year_month_day::day() const NOEXCEPT { return d_; } - -template -CONSTCD14 inline year_month_day& year_month_day::operator+=(const months& m) NOEXCEPT { - *this = *this + m; - return *this; -} - -template -CONSTCD14 inline year_month_day& year_month_day::operator-=(const months& m) NOEXCEPT { - *this = *this - m; - return *this; -} - -CONSTCD14 -inline year_month_day& year_month_day::operator+=(const years& y) NOEXCEPT { - *this = *this + y; - return *this; -} - -CONSTCD14 -inline year_month_day& year_month_day::operator-=(const years& y) NOEXCEPT { - *this = *this - y; - return *this; -} - -CONSTCD14 -inline days year_month_day::to_days() const NOEXCEPT { - static_assert(std::numeric_limits::digits >= 18, "This algorithm has not been ported to a 16 bit unsigned integer"); - static_assert(std::numeric_limits::digits >= 20, "This algorithm has not been ported to a 16 bit signed integer"); - auto const y = static_cast(y_) - (m_ <= February); - auto const m = static_cast(m_); - auto const d = static_cast(d_); - auto const era = (y >= 0 ? y : y - 399) / 400; - auto const yoe = static_cast(y - era * 400); // [0, 399] - auto const doy = (153 * (m > 2 ? m - 3 : m + 9) + 2) / 5 + d - 1; // [0, 365] - auto const doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; // [0, 146096] - return days{era * 146097 + static_cast(doe) - 719468}; -} - -CONSTCD14 -inline year_month_day::operator sys_days() const NOEXCEPT { return sys_days{to_days()}; } - -CONSTCD14 -inline year_month_day::operator local_days() const NOEXCEPT { return local_days{to_days()}; } - -CONSTCD14 -inline bool year_month_day::ok() const NOEXCEPT { - if (!(y_.ok() && m_.ok())) return false; - return date::day{1} <= d_ && d_ <= (y_ / m_ / last).day(); -} - -CONSTCD11 -inline bool operator==(const year_month_day& x, const year_month_day& y) NOEXCEPT { - return x.year() == y.year() && x.month() == y.month() && x.day() == y.day(); -} - -CONSTCD11 -inline bool operator!=(const year_month_day& x, const year_month_day& y) NOEXCEPT { return !(x == y); } - -CONSTCD11 -inline bool operator<(const year_month_day& x, const year_month_day& y) NOEXCEPT { - return x.year() < y.year() ? true : (x.year() > y.year() ? false : (x.month() < y.month() ? true : (x.month() > y.month() ? false : (x.day() < y.day())))); -} - -CONSTCD11 -inline bool operator>(const year_month_day& x, const year_month_day& y) NOEXCEPT { return y < x; } - -CONSTCD11 -inline bool operator<=(const year_month_day& x, const year_month_day& y) NOEXCEPT { return !(y < x); } - -CONSTCD11 -inline bool operator>=(const year_month_day& x, const year_month_day& y) NOEXCEPT { return !(x < y); } - -template -inline std::basic_ostream& operator<<(std::basic_ostream& os, const year_month_day& ymd) { - detail::save_ostream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.imbue(std::locale::classic()); - os << ymd.year() << '-'; - os.width(2); - os << static_cast(ymd.month()) << '-'; - os << ymd.day(); - if (!ymd.ok()) os << " is not a valid date"; - return os; -} - -CONSTCD14 -inline year_month_day year_month_day::from_days(days dp) NOEXCEPT { - static_assert(std::numeric_limits::digits >= 18, "This algorithm has not been ported to a 16 bit unsigned integer"); - static_assert(std::numeric_limits::digits >= 20, "This algorithm has not been ported to a 16 bit signed integer"); - auto const z = dp.count() + 719468; - auto const era = (z >= 0 ? z : z - 146096) / 146097; - auto const doe = static_cast(z - era * 146097); // [0, 146096] - auto const yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365; // [0, 399] - auto const y = static_cast(yoe) + era * 400; - auto const doy = doe - (365 * yoe + yoe / 4 - yoe / 100); // [0, 365] - auto const mp = (5 * doy + 2) / 153; // [0, 11] - auto const d = doy - (153 * mp + 2) / 5 + 1; // [1, 31] - auto const m = mp < 10 ? mp + 3 : mp - 9; // [1, 12] - return year_month_day{date::year{y + (m <= 2)}, date::month(m), date::day(d)}; -} - -template -CONSTCD14 inline year_month_day operator+(const year_month_day& ymd, const months& dm) NOEXCEPT { - return (ymd.year() / ymd.month() + dm) / ymd.day(); -} - -template -CONSTCD14 inline year_month_day operator+(const months& dm, const year_month_day& ymd) NOEXCEPT { - return ymd + dm; -} - -template -CONSTCD14 inline year_month_day operator-(const year_month_day& ymd, const months& dm) NOEXCEPT { - return ymd + (-dm); -} - -CONSTCD11 -inline year_month_day operator+(const year_month_day& ymd, const years& dy) NOEXCEPT { return (ymd.year() + dy) / ymd.month() / ymd.day(); } - -CONSTCD11 -inline year_month_day operator+(const years& dy, const year_month_day& ymd) NOEXCEPT { return ymd + dy; } - -CONSTCD11 -inline year_month_day operator-(const year_month_day& ymd, const years& dy) NOEXCEPT { return ymd + (-dy); } - -// year_month_weekday - -CONSTCD11 -inline year_month_weekday::year_month_weekday(const date::year& y, const date::month& m, const date::weekday_indexed& wdi) NOEXCEPT : y_(y), m_(m), wdi_(wdi) {} - -CONSTCD14 -inline year_month_weekday::year_month_weekday(const sys_days& dp) NOEXCEPT : year_month_weekday(from_days(dp.time_since_epoch())) {} - -CONSTCD14 -inline year_month_weekday::year_month_weekday(const local_days& dp) NOEXCEPT : year_month_weekday(from_days(dp.time_since_epoch())) {} - -template -CONSTCD14 inline year_month_weekday& year_month_weekday::operator+=(const months& m) NOEXCEPT { - *this = *this + m; - return *this; -} - -template -CONSTCD14 inline year_month_weekday& year_month_weekday::operator-=(const months& m) NOEXCEPT { - *this = *this - m; - return *this; -} - -CONSTCD14 -inline year_month_weekday& year_month_weekday::operator+=(const years& y) NOEXCEPT { - *this = *this + y; - return *this; -} - -CONSTCD14 -inline year_month_weekday& year_month_weekday::operator-=(const years& y) NOEXCEPT { - *this = *this - y; - return *this; -} - -CONSTCD11 inline year year_month_weekday::year() const NOEXCEPT { return y_; } -CONSTCD11 inline month year_month_weekday::month() const NOEXCEPT { return m_; } - -CONSTCD11 -inline weekday year_month_weekday::weekday() const NOEXCEPT { return wdi_.weekday(); } - -CONSTCD11 -inline unsigned year_month_weekday::index() const NOEXCEPT { return wdi_.index(); } - -CONSTCD11 -inline weekday_indexed year_month_weekday::weekday_indexed() const NOEXCEPT { return wdi_; } - -CONSTCD14 -inline year_month_weekday::operator sys_days() const NOEXCEPT { return sys_days{to_days()}; } - -CONSTCD14 -inline year_month_weekday::operator local_days() const NOEXCEPT { return local_days{to_days()}; } - -CONSTCD14 -inline bool year_month_weekday::ok() const NOEXCEPT { - if (!y_.ok() || !m_.ok() || !wdi_.weekday().ok() || wdi_.index() < 1) return false; - if (wdi_.index() <= 4) return true; - auto d2 = wdi_.weekday() - date::weekday(static_cast(y_ / m_ / 1)) + days((wdi_.index() - 1) * 7 + 1); - return static_cast(d2.count()) <= static_cast((y_ / m_ / last).day()); -} - -CONSTCD14 -inline year_month_weekday year_month_weekday::from_days(days d) NOEXCEPT { - sys_days dp{d}; - auto const wd = date::weekday(dp); - auto const ymd = year_month_day(dp); - return {ymd.year(), ymd.month(), wd[(static_cast(ymd.day()) - 1) / 7 + 1]}; -} - -CONSTCD14 -inline days year_month_weekday::to_days() const NOEXCEPT { - auto d = sys_days(y_ / m_ / 1); - return (d + (wdi_.weekday() - date::weekday(d) + days{(wdi_.index() - 1) * 7})).time_since_epoch(); -} - -CONSTCD11 -inline bool operator==(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT { - return x.year() == y.year() && x.month() == y.month() && x.weekday_indexed() == y.weekday_indexed(); -} - -CONSTCD11 -inline bool operator!=(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT { return !(x == y); } - -template -inline std::basic_ostream& operator<<(std::basic_ostream& os, const year_month_weekday& ymwdi) { - return os << ymwdi.year() << '/' << ymwdi.month() << '/' << ymwdi.weekday_indexed(); -} - -template -CONSTCD14 inline year_month_weekday operator+(const year_month_weekday& ymwd, const months& dm) NOEXCEPT { - return (ymwd.year() / ymwd.month() + dm) / ymwd.weekday_indexed(); -} - -template -CONSTCD14 inline year_month_weekday operator+(const months& dm, const year_month_weekday& ymwd) NOEXCEPT { - return ymwd + dm; -} - -template -CONSTCD14 inline year_month_weekday operator-(const year_month_weekday& ymwd, const months& dm) NOEXCEPT { - return ymwd + (-dm); -} - -CONSTCD11 -inline year_month_weekday operator+(const year_month_weekday& ymwd, const years& dy) NOEXCEPT { - return {ymwd.year() + dy, ymwd.month(), ymwd.weekday_indexed()}; -} - -CONSTCD11 -inline year_month_weekday operator+(const years& dy, const year_month_weekday& ymwd) NOEXCEPT { return ymwd + dy; } - -CONSTCD11 -inline year_month_weekday operator-(const year_month_weekday& ymwd, const years& dy) NOEXCEPT { return ymwd + (-dy); } - -// year_month_weekday_last - -CONSTCD11 -inline year_month_weekday_last::year_month_weekday_last(const date::year& y, const date::month& m, const date::weekday_last& wdl) NOEXCEPT : y_(y), - m_(m), - wdl_(wdl) {} - -template -CONSTCD14 inline year_month_weekday_last& year_month_weekday_last::operator+=(const months& m) NOEXCEPT { - *this = *this + m; - return *this; -} - -template -CONSTCD14 inline year_month_weekday_last& year_month_weekday_last::operator-=(const months& m) NOEXCEPT { - *this = *this - m; - return *this; -} - -CONSTCD14 -inline year_month_weekday_last& year_month_weekday_last::operator+=(const years& y) NOEXCEPT { - *this = *this + y; - return *this; -} - -CONSTCD14 -inline year_month_weekday_last& year_month_weekday_last::operator-=(const years& y) NOEXCEPT { - *this = *this - y; - return *this; -} - -CONSTCD11 inline year year_month_weekday_last::year() const NOEXCEPT { return y_; } -CONSTCD11 inline month year_month_weekday_last::month() const NOEXCEPT { return m_; } - -CONSTCD11 -inline weekday year_month_weekday_last::weekday() const NOEXCEPT { return wdl_.weekday(); } - -CONSTCD11 -inline weekday_last year_month_weekday_last::weekday_last() const NOEXCEPT { return wdl_; } - -CONSTCD14 -inline year_month_weekday_last::operator sys_days() const NOEXCEPT { return sys_days{to_days()}; } - -CONSTCD14 -inline year_month_weekday_last::operator local_days() const NOEXCEPT { return local_days{to_days()}; } - -CONSTCD11 -inline bool year_month_weekday_last::ok() const NOEXCEPT { return y_.ok() && m_.ok() && wdl_.ok(); } - -CONSTCD14 -inline days year_month_weekday_last::to_days() const NOEXCEPT { - auto const d = sys_days(y_ / m_ / last); - return (d - (date::weekday{d} - wdl_.weekday())).time_since_epoch(); -} - -CONSTCD11 -inline bool operator==(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT { - return x.year() == y.year() && x.month() == y.month() && x.weekday_last() == y.weekday_last(); -} - -CONSTCD11 -inline bool operator!=(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT { return !(x == y); } - -template -inline std::basic_ostream& operator<<(std::basic_ostream& os, const year_month_weekday_last& ymwdl) { - return os << ymwdl.year() << '/' << ymwdl.month() << '/' << ymwdl.weekday_last(); -} - -template -CONSTCD14 inline year_month_weekday_last operator+(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT { - return (ymwdl.year() / ymwdl.month() + dm) / ymwdl.weekday_last(); -} - -template -CONSTCD14 inline year_month_weekday_last operator+(const months& dm, const year_month_weekday_last& ymwdl) NOEXCEPT { - return ymwdl + dm; -} - -template -CONSTCD14 inline year_month_weekday_last operator-(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT { - return ymwdl + (-dm); -} - -CONSTCD11 -inline year_month_weekday_last operator+(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT { - return {ymwdl.year() + dy, ymwdl.month(), ymwdl.weekday_last()}; -} - -CONSTCD11 -inline year_month_weekday_last operator+(const years& dy, const year_month_weekday_last& ymwdl) NOEXCEPT { return ymwdl + dy; } - -CONSTCD11 -inline year_month_weekday_last operator-(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT { return ymwdl + (-dy); } - -// year_month from operator/() - -CONSTCD11 -inline year_month operator/(const year& y, const month& m) NOEXCEPT { return {y, m}; } - -CONSTCD11 -inline year_month operator/(const year& y, int m) NOEXCEPT { return y / month(static_cast(m)); } - -// month_day from operator/() - -CONSTCD11 -inline month_day operator/(const month& m, const day& d) NOEXCEPT { return {m, d}; } - -CONSTCD11 -inline month_day operator/(const day& d, const month& m) NOEXCEPT { return m / d; } - -CONSTCD11 -inline month_day operator/(const month& m, int d) NOEXCEPT { return m / day(static_cast(d)); } - -CONSTCD11 -inline month_day operator/(int m, const day& d) NOEXCEPT { return month(static_cast(m)) / d; } - -CONSTCD11 inline month_day operator/(const day& d, int m) NOEXCEPT { return m / d; } - -// month_day_last from operator/() - -CONSTCD11 -inline month_day_last operator/(const month& m, last_spec) NOEXCEPT { return month_day_last{m}; } - -CONSTCD11 -inline month_day_last operator/(last_spec, const month& m) NOEXCEPT { return m / last; } - -CONSTCD11 -inline month_day_last operator/(int m, last_spec) NOEXCEPT { return month(static_cast(m)) / last; } - -CONSTCD11 -inline month_day_last operator/(last_spec, int m) NOEXCEPT { return m / last; } - -// month_weekday from operator/() - -CONSTCD11 -inline month_weekday operator/(const month& m, const weekday_indexed& wdi) NOEXCEPT { return {m, wdi}; } - -CONSTCD11 -inline month_weekday operator/(const weekday_indexed& wdi, const month& m) NOEXCEPT { return m / wdi; } - -CONSTCD11 -inline month_weekday operator/(int m, const weekday_indexed& wdi) NOEXCEPT { return month(static_cast(m)) / wdi; } - -CONSTCD11 -inline month_weekday operator/(const weekday_indexed& wdi, int m) NOEXCEPT { return m / wdi; } - -// month_weekday_last from operator/() - -CONSTCD11 -inline month_weekday_last operator/(const month& m, const weekday_last& wdl) NOEXCEPT { return {m, wdl}; } - -CONSTCD11 -inline month_weekday_last operator/(const weekday_last& wdl, const month& m) NOEXCEPT { return m / wdl; } - -CONSTCD11 -inline month_weekday_last operator/(int m, const weekday_last& wdl) NOEXCEPT { return month(static_cast(m)) / wdl; } - -CONSTCD11 -inline month_weekday_last operator/(const weekday_last& wdl, int m) NOEXCEPT { return m / wdl; } - -// year_month_day from operator/() - -CONSTCD11 -inline year_month_day operator/(const year_month& ym, const day& d) NOEXCEPT { return {ym.year(), ym.month(), d}; } - -CONSTCD11 -inline year_month_day operator/(const year_month& ym, int d) NOEXCEPT { return ym / day(static_cast(d)); } - -CONSTCD11 -inline year_month_day operator/(const year& y, const month_day& md) NOEXCEPT { return y / md.month() / md.day(); } - -CONSTCD11 -inline year_month_day operator/(int y, const month_day& md) NOEXCEPT { return year(y) / md; } - -CONSTCD11 -inline year_month_day operator/(const month_day& md, const year& y) NOEXCEPT { return y / md; } - -CONSTCD11 -inline year_month_day operator/(const month_day& md, int y) NOEXCEPT { return year(y) / md; } - -// year_month_day_last from operator/() - -CONSTCD11 -inline year_month_day_last operator/(const year_month& ym, last_spec) NOEXCEPT { return {ym.year(), month_day_last{ym.month()}}; } - -CONSTCD11 -inline year_month_day_last operator/(const year& y, const month_day_last& mdl) NOEXCEPT { return {y, mdl}; } - -CONSTCD11 -inline year_month_day_last operator/(int y, const month_day_last& mdl) NOEXCEPT { return year(y) / mdl; } - -CONSTCD11 -inline year_month_day_last operator/(const month_day_last& mdl, const year& y) NOEXCEPT { return y / mdl; } - -CONSTCD11 -inline year_month_day_last operator/(const month_day_last& mdl, int y) NOEXCEPT { return year(y) / mdl; } - -// year_month_weekday from operator/() - -CONSTCD11 -inline year_month_weekday operator/(const year_month& ym, const weekday_indexed& wdi) NOEXCEPT { return {ym.year(), ym.month(), wdi}; } - -CONSTCD11 -inline year_month_weekday operator/(const year& y, const month_weekday& mwd) NOEXCEPT { return {y, mwd.month(), mwd.weekday_indexed()}; } - -CONSTCD11 -inline year_month_weekday operator/(int y, const month_weekday& mwd) NOEXCEPT { return year(y) / mwd; } - -CONSTCD11 -inline year_month_weekday operator/(const month_weekday& mwd, const year& y) NOEXCEPT { return y / mwd; } - -CONSTCD11 -inline year_month_weekday operator/(const month_weekday& mwd, int y) NOEXCEPT { return year(y) / mwd; } - -// year_month_weekday_last from operator/() - -CONSTCD11 -inline year_month_weekday_last operator/(const year_month& ym, const weekday_last& wdl) NOEXCEPT { return {ym.year(), ym.month(), wdl}; } - -CONSTCD11 -inline year_month_weekday_last operator/(const year& y, const month_weekday_last& mwdl) NOEXCEPT { return {y, mwdl.month(), mwdl.weekday_last()}; } - -CONSTCD11 -inline year_month_weekday_last operator/(int y, const month_weekday_last& mwdl) NOEXCEPT { return year(y) / mwdl; } - -CONSTCD11 -inline year_month_weekday_last operator/(const month_weekday_last& mwdl, const year& y) NOEXCEPT { return y / mwdl; } - -CONSTCD11 -inline year_month_weekday_last operator/(const month_weekday_last& mwdl, int y) NOEXCEPT { return year(y) / mwdl; } - -template -struct fields; - -template -std::basic_ostream& to_stream(std::basic_ostream& os, const CharT* fmt, const fields& fds, - const std::string* abbrev = nullptr, const std::chrono::seconds* offset_sec = nullptr); - -template -std::basic_istream& from_stream(std::basic_istream& is, const CharT* fmt, fields& fds, - std::basic_string* abbrev = nullptr, std::chrono::minutes* offset = nullptr); - -// hh_mm_ss - -namespace detail { - -struct undocumented { - explicit undocumented() = default; -}; - -// width::value is the number of fractional decimal digits in 1/n -// width<0>::value and width<1>::value are defined to be 0 -// If 1/n takes more than 18 fractional decimal digits, -// the result is truncated to 19. -// Example: width<2>::value == 1 -// Example: width<3>::value == 19 -// Example: width<4>::value == 2 -// Example: width<10>::value == 1 -// Example: width<1000>::value == 3 -template -struct width { - static CONSTDATA unsigned value = 1 + width::value; -}; - -template -struct width { - static CONSTDATA unsigned value = 0; -}; - -template -struct static_pow10 { - private: - static CONSTDATA std::uint64_t h = static_pow10::value; - - public: - static CONSTDATA std::uint64_t value = h * h * (exp % 2 ? 10 : 1); -}; - -template <> -struct static_pow10<0> { - static CONSTDATA std::uint64_t value = 1; -}; - -template -class decimal_format_seconds { - using CT = typename std::common_type::type; - using rep = typename CT::rep; - - public: - static unsigned constexpr width = detail::width::value < 19 ? detail::width::value : 6u; - using precision = std::chrono::duration::value>>; - - private: - std::chrono::seconds s_; - precision sub_s_; - - public: - CONSTCD11 decimal_format_seconds() : s_(), sub_s_() {} - - CONSTCD11 explicit decimal_format_seconds(const Duration& d) NOEXCEPT : s_(std::chrono::duration_cast(d)), - sub_s_(std::chrono::duration_cast(d - s_)) {} - - CONSTCD14 std::chrono::seconds& seconds() NOEXCEPT { return s_; } - CONSTCD11 std::chrono::seconds seconds() const NOEXCEPT { return s_; } - CONSTCD11 precision subseconds() const NOEXCEPT { return sub_s_; } - - CONSTCD14 precision to_duration() const NOEXCEPT { return s_ + sub_s_; } - - CONSTCD11 bool in_conventional_range() const NOEXCEPT { return sub_s_ < std::chrono::seconds{1} && s_ < std::chrono::minutes{1}; } - - template - friend std::basic_ostream& operator<<(std::basic_ostream& os, const decimal_format_seconds& x) { - return x.print(os, std::chrono::treat_as_floating_point{}); - } - - template - std::basic_ostream& print(std::basic_ostream& os, std::true_type) const { - date::detail::save_ostream _(os); - std::chrono::duration d = s_ + sub_s_; - if (d < std::chrono::seconds{10}) os << '0'; - os << std::fixed << d.count(); - return os; - } - - template - std::basic_ostream& print(std::basic_ostream& os, std::false_type) const { - date::detail::save_ostream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(2); - os << s_.count(); - if (width > 0) { -#if !ONLY_C_LOCALE - os << std::use_facet>(os.getloc()).decimal_point(); -#else - os << '.'; -#endif - date::detail::save_ostream _s(os); - os.imbue(std::locale::classic()); - os.width(width); - os << sub_s_.count(); - } - return os; - } -}; - -template -inline CONSTCD11 typename std::enable_if::is_signed, std::chrono::duration>::type abs( - std::chrono::duration d) { - return d >= d.zero() ? +d : -d; -} - -template -inline CONSTCD11 typename std::enable_if::is_signed, std::chrono::duration>::type abs( - std::chrono::duration d) { - return d; -} - -} // namespace detail - -template -class hh_mm_ss { - using dfs = detail::decimal_format_seconds::type>; - - std::chrono::hours h_; - std::chrono::minutes m_; - dfs s_; - bool neg_; - - public: - static unsigned CONSTDATA fractional_width = dfs::width; - using precision = typename dfs::precision; - - CONSTCD11 hh_mm_ss() NOEXCEPT : hh_mm_ss(Duration::zero()) {} - - CONSTCD11 explicit hh_mm_ss(Duration d) NOEXCEPT : h_(std::chrono::duration_cast(detail::abs(d))), - m_(std::chrono::duration_cast(detail::abs(d)) - h_), - s_(detail::abs(d) - h_ - m_), - neg_(d < Duration::zero()) {} - - CONSTCD11 std::chrono::hours hours() const NOEXCEPT { return h_; } - CONSTCD11 std::chrono::minutes minutes() const NOEXCEPT { return m_; } - CONSTCD11 std::chrono::seconds seconds() const NOEXCEPT { return s_.seconds(); } - CONSTCD14 std::chrono::seconds& seconds(detail::undocumented) NOEXCEPT { return s_.seconds(); } - CONSTCD11 precision subseconds() const NOEXCEPT { return s_.subseconds(); } - CONSTCD11 bool is_negative() const NOEXCEPT { return neg_; } - - CONSTCD11 explicit operator precision() const NOEXCEPT { return to_duration(); } - CONSTCD11 precision to_duration() const NOEXCEPT { return (s_.to_duration() + m_ + h_) * (1 - 2 * neg_); } - - CONSTCD11 bool in_conventional_range() const NOEXCEPT { return !neg_ && h_ < days{1} && m_ < std::chrono::hours{1} && s_.in_conventional_range(); } - - private: - template - friend std::basic_ostream& operator<<(std::basic_ostream& os, hh_mm_ss const& tod) { - if (tod.is_negative()) os << '-'; - if (tod.h_ < std::chrono::hours{10}) os << '0'; - os << tod.h_.count() << ':'; - if (tod.m_ < std::chrono::minutes{10}) os << '0'; - os << tod.m_.count() << ':' << tod.s_; - return os; - } - - template - friend std::basic_ostream& date::to_stream(std::basic_ostream& os, const CharT* fmt, const fields& fds, - const std::string* abbrev, const std::chrono::seconds* offset_sec); - - template - friend std::basic_istream& date::from_stream(std::basic_istream& is, const CharT* fmt, fields& fds, - std::basic_string* abbrev, std::chrono::minutes* offset); -}; - -inline CONSTCD14 bool is_am(std::chrono::hours const& h) NOEXCEPT { - using std::chrono::hours; - return hours{0} <= h && h < hours{12}; -} - -inline CONSTCD14 bool is_pm(std::chrono::hours const& h) NOEXCEPT { - using std::chrono::hours; - return hours{12} <= h && h < hours{24}; -} - -inline CONSTCD14 std::chrono::hours make12(std::chrono::hours h) NOEXCEPT { - using std::chrono::hours; - if (h < hours{12}) { - if (h == hours{0}) h = hours{12}; - } else { - if (h != hours{12}) h = h - hours{12}; - } - return h; -} - -inline CONSTCD14 std::chrono::hours make24(std::chrono::hours h, bool is_pm) NOEXCEPT { - using std::chrono::hours; - if (is_pm) { - if (h != hours{12}) h = h + hours{12}; - } else if (h == hours{12}) - h = hours{0}; - return h; -} - -template -using time_of_day = hh_mm_ss; - -template ::value>::type> -CONSTCD11 inline hh_mm_ss> make_time(const std::chrono::duration& d) { - return hh_mm_ss>(d); -} - -template -inline typename std::enable_if::value && - std::ratio_less::value, - std::basic_ostream&>::type -operator<<(std::basic_ostream& os, const sys_time& tp) { - auto const dp = date::floor(tp); - return os << year_month_day(dp) << ' ' << make_time(tp - dp); -} - -template -inline std::basic_ostream& operator<<(std::basic_ostream& os, const sys_days& dp) { - return os << year_month_day(dp); -} - -template -inline std::basic_ostream& operator<<(std::basic_ostream& os, const local_time& ut) { - return (os << sys_time{ut.time_since_epoch()}); -} - -namespace detail { - -template -class string_literal; - -template -inline CONSTCD14 string_literal::type, N1 + N2 - 1> operator+( - const string_literal& x, const string_literal& y) NOEXCEPT; - -template -class string_literal { - CharT p_[N]; - - CONSTCD11 string_literal() NOEXCEPT : p_{} {} - - public: - using const_iterator = const CharT*; - - string_literal(string_literal const&) = default; - string_literal& operator=(string_literal const&) = delete; - - template ::type> - CONSTCD11 string_literal(CharT c) NOEXCEPT : p_{c} {} - - template ::type> - CONSTCD11 string_literal(CharT c1, CharT c2) NOEXCEPT : p_{c1, c2} {} - - template ::type> - CONSTCD11 string_literal(CharT c1, CharT c2, CharT c3) NOEXCEPT : p_{c1, c2, c3} {} - - CONSTCD14 string_literal(const CharT (&a)[N]) NOEXCEPT : p_{} { - for (std::size_t i = 0; i < N; ++i) p_[i] = a[i]; - } - - template ::type> - CONSTCD14 string_literal(const char (&a)[N]) NOEXCEPT : p_{} { - for (std::size_t i = 0; i < N; ++i) p_[i] = a[i]; - } - - template ::value>::type> - CONSTCD14 string_literal(string_literal const& a) NOEXCEPT : p_{} { - for (std::size_t i = 0; i < N; ++i) p_[i] = a[i]; - } - - CONSTCD11 const CharT* data() const NOEXCEPT { return p_; } - CONSTCD11 std::size_t size() const NOEXCEPT { return N - 1; } - - CONSTCD11 const_iterator begin() const NOEXCEPT { return p_; } - CONSTCD11 const_iterator end() const NOEXCEPT { return p_ + N - 1; } - - CONSTCD11 CharT const& operator[](std::size_t n) const NOEXCEPT { return p_[n]; } - - template - friend std::basic_ostream& operator<<(std::basic_ostream& os, const string_literal& s) { - return os << s.p_; - } - - template - friend CONSTCD14 string_literal::type, N1 + N2 - 1> operator+( - const string_literal& x, const string_literal& y) NOEXCEPT; -}; - -template -CONSTCD11 inline string_literal operator+(const string_literal& x, const string_literal& y) NOEXCEPT { - return string_literal(x[0], y[0]); -} - -template -CONSTCD11 inline string_literal operator+(const string_literal& x, const string_literal& y) NOEXCEPT { - return string_literal(x[0], x[1], y[0]); -} - -template -CONSTCD14 inline string_literal::type, N1 + N2 - 1> operator+( - const string_literal& x, const string_literal& y) NOEXCEPT { - using CT = typename std::conditional::type; - - string_literal r; - std::size_t i = 0; - for (; i < N1 - 1; ++i) r.p_[i] = CT(x.p_[i]); - for (std::size_t j = 0; j < N2; ++j, ++i) r.p_[i] = CT(y.p_[j]); - - return r; -} - -template -inline std::basic_string operator+(std::basic_string x, const string_literal& y) { - x.append(y.data(), y.size()); - return x; -} - -#if __cplusplus >= 201402 && (!defined(__EDG_VERSION__) || __EDG_VERSION__ > 411) && (!defined(__SUNPRO_CC) || __SUNPRO_CC > 0x5150) - -template ::value || std::is_same::value || - std::is_same::value || std::is_same::value>> -CONSTCD14 inline string_literal msl(CharT c) NOEXCEPT { - return string_literal{c}; -} - -CONSTCD14 -inline std::size_t to_string_len(std::intmax_t i) { - std::size_t r = 0; - do { - i /= 10; - ++r; - } while (i > 0); - return r; -} - -template - CONSTCD14 inline std::enable_if_t < N<10, string_literal> msl() NOEXCEPT { - return msl(char(N % 10 + '0')); -} - -template -CONSTCD14 inline std::enable_if_t<10 <= N, string_literal> msl() NOEXCEPT { - return msl() + msl(char(N % 10 + '0')); -} - -template -CONSTCD14 inline std::enable_if_t::type::den != 1, - string_literal::type::num) + to_string_len(std::ratio::type::den) + 4>> -msl(std::ratio) NOEXCEPT { - using R = typename std::ratio::type; - return msl(CharT{'['}) + msl() + msl(CharT{'/'}) + msl() + msl(CharT{']'}); -} - -template -CONSTCD14 inline std::enable_if_t::type::den == 1, string_literal::type::num) + 3>> msl( - std::ratio) NOEXCEPT { - using R = typename std::ratio::type; - return msl(CharT{'['}) + msl() + msl(CharT{']'}); -} - -#else // __cplusplus < 201402 || (defined(__EDG_VERSION__) && __EDG_VERSION__ <= 411) - -inline std::string to_string(std::uint64_t x) { return std::to_string(x); } - -template -inline std::basic_string to_string(std::uint64_t x) { - auto y = std::to_string(x); - return std::basic_string(y.begin(), y.end()); -} - -template -inline typename std::enable_if::type::den != 1, std::basic_string>::type msl(std::ratio) { - using R = typename std::ratio::type; - return std::basic_string(1, '[') + to_string(R::num) + CharT{'/'} + to_string(R::den) + CharT{']'}; -} - -template -inline typename std::enable_if::type::den == 1, std::basic_string>::type msl(std::ratio) { - using R = typename std::ratio::type; - return std::basic_string(1, '[') + to_string(R::num) + CharT{']'}; -} - -#endif // __cplusplus < 201402 || (defined(__EDG_VERSION__) && __EDG_VERSION__ <= 411) - -template -CONSTCD11 inline string_literal msl(std::atto) NOEXCEPT { - return string_literal{'a'}; -} - -template -CONSTCD11 inline string_literal msl(std::femto) NOEXCEPT { - return string_literal{'f'}; -} - -template -CONSTCD11 inline string_literal msl(std::pico) NOEXCEPT { - return string_literal{'p'}; -} - -template -CONSTCD11 inline string_literal msl(std::nano) NOEXCEPT { - return string_literal{'n'}; -} - -template -CONSTCD11 inline typename std::enable_if::value, string_literal>::type msl(std::micro) NOEXCEPT { - return string_literal{'\xC2', '\xB5'}; -} - -template -CONSTCD11 inline typename std::enable_if::value, string_literal>::type msl(std::micro) NOEXCEPT { - return string_literal{CharT{static_cast('\xB5')}}; -} - -template -CONSTCD11 inline string_literal msl(std::milli) NOEXCEPT { - return string_literal{'m'}; -} - -template -CONSTCD11 inline string_literal msl(std::centi) NOEXCEPT { - return string_literal{'c'}; -} - -template -CONSTCD11 inline string_literal msl(std::deca) NOEXCEPT { - return string_literal{'d', 'a'}; -} - -template -CONSTCD11 inline string_literal msl(std::deci) NOEXCEPT { - return string_literal{'d'}; -} - -template -CONSTCD11 inline string_literal msl(std::hecto) NOEXCEPT { - return string_literal{'h'}; -} - -template -CONSTCD11 inline string_literal msl(std::kilo) NOEXCEPT { - return string_literal{'k'}; -} - -template -CONSTCD11 inline string_literal msl(std::mega) NOEXCEPT { - return string_literal{'M'}; -} - -template -CONSTCD11 inline string_literal msl(std::giga) NOEXCEPT { - return string_literal{'G'}; -} - -template -CONSTCD11 inline string_literal msl(std::tera) NOEXCEPT { - return string_literal{'T'}; -} - -template -CONSTCD11 inline string_literal msl(std::peta) NOEXCEPT { - return string_literal{'P'}; -} - -template -CONSTCD11 inline string_literal msl(std::exa) NOEXCEPT { - return string_literal{'E'}; -} - -template -CONSTCD11 inline auto get_units(Period p) -> decltype(msl(p) + string_literal{'s'}) { - return msl(p) + string_literal{'s'}; -} - -template -CONSTCD11 inline string_literal get_units(std::ratio<1>) { - return string_literal{'s'}; -} - -template -CONSTCD11 inline string_literal get_units(std::ratio<3600>) { - return string_literal{'h'}; -} - -template -CONSTCD11 inline string_literal get_units(std::ratio<60>) { - return string_literal{'m', 'i', 'n'}; -} - -template -CONSTCD11 inline string_literal get_units(std::ratio<86400>) { - return string_literal{'d'}; -} - -template > -struct make_string; - -template <> -struct make_string { - template - static std::string from(Rep n) { - return std::to_string(n); - } -}; - -template -struct make_string { - template - static std::basic_string from(Rep n) { - auto s = std::to_string(n); - return std::basic_string(s.begin(), s.end()); - } -}; - -template <> -struct make_string { - template - static std::wstring from(Rep n) { - return std::to_wstring(n); - } -}; - -template -struct make_string { - template - static std::basic_string from(Rep n) { - auto s = std::to_wstring(n); - return std::basic_string(s.begin(), s.end()); - } -}; - -} // namespace detail - -// to_stream - -CONSTDATA year nanyear{-32768}; - -template -struct fields { - year_month_day ymd{nanyear / 0 / 0}; - weekday wd{8u}; - hh_mm_ss tod{}; - bool has_tod = false; - - fields() = default; - - fields(year_month_day ymd_) : ymd(ymd_) {} - fields(weekday wd_) : wd(wd_) {} - fields(hh_mm_ss tod_) : tod(tod_), has_tod(true) {} - - fields(year_month_day ymd_, weekday wd_) : ymd(ymd_), wd(wd_) {} - fields(year_month_day ymd_, hh_mm_ss tod_) : ymd(ymd_), tod(tod_), has_tod(true) {} - - fields(weekday wd_, hh_mm_ss tod_) : wd(wd_), tod(tod_), has_tod(true) {} - - fields(year_month_day ymd_, weekday wd_, hh_mm_ss tod_) : ymd(ymd_), wd(wd_), tod(tod_), has_tod(true) {} -}; - -namespace detail { - -template -unsigned extract_weekday(std::basic_ostream& os, const fields& fds) { - if (!fds.ymd.ok() && !fds.wd.ok()) { - // fds does not contain a valid weekday - os.setstate(std::ios::failbit); - return 8; - } - weekday wd; - if (fds.ymd.ok()) { - wd = weekday{sys_days(fds.ymd)}; - if (fds.wd.ok() && wd != fds.wd) { - // fds.ymd and fds.wd are inconsistent - os.setstate(std::ios::failbit); - return 8; - } - } else - wd = fds.wd; - return static_cast((wd - Sunday).count()); -} - -template -unsigned extract_month(std::basic_ostream& os, const fields& fds) { - if (!fds.ymd.month().ok()) { - // fds does not contain a valid month - os.setstate(std::ios::failbit); - return 0; - } - return static_cast(fds.ymd.month()); -} - -} // namespace detail - -#if ONLY_C_LOCALE - -namespace detail { - -inline std::pair weekday_names() { - static const std::string nm[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", - "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; - return std::make_pair(nm, nm + sizeof(nm) / sizeof(nm[0])); -} - -inline std::pair month_names() { - static const std::string nm[] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", - "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; - return std::make_pair(nm, nm + sizeof(nm) / sizeof(nm[0])); -} - -inline std::pair ampm_names() { - static const std::string nm[] = {"AM", "PM"}; - return std::make_pair(nm, nm + sizeof(nm) / sizeof(nm[0])); -} - -template -FwdIter scan_keyword(std::basic_istream& is, FwdIter kb, FwdIter ke) { - size_t nkw = static_cast(std::distance(kb, ke)); - const unsigned char doesnt_match = '\0'; - const unsigned char might_match = '\1'; - const unsigned char does_match = '\2'; - unsigned char statbuf[100]; - unsigned char* status = statbuf; - std::unique_ptr stat_hold(0, free); - if (nkw > sizeof(statbuf)) { - status = (unsigned char*)std::malloc(nkw); - if (status == nullptr) throw std::bad_alloc(); - stat_hold.reset(status); - } - size_t n_might_match = nkw; // At this point, any keyword might match - size_t n_does_match = 0; // but none of them definitely do - // Initialize all statuses to might_match, except for "" keywords are does_match - unsigned char* st = status; - for (auto ky = kb; ky != ke; ++ky, ++st) { - if (!ky->empty()) - *st = might_match; - else { - *st = does_match; - --n_might_match; - ++n_does_match; - } - } - // While there might be a match, test keywords against the next CharT - for (size_t indx = 0; is && n_might_match > 0; ++indx) { - // Peek at the next CharT but don't consume it - auto ic = is.peek(); - if (ic == EOF) { - is.setstate(std::ios::eofbit); - break; - } - auto c = static_cast(toupper(ic)); - bool consume = false; - // For each keyword which might match, see if the indx character is c - // If a match if found, consume c - // If a match is found, and that is the last character in the keyword, - // then that keyword matches. - // If the keyword doesn't match this character, then change the keyword - // to doesn't match - st = status; - for (auto ky = kb; ky != ke; ++ky, ++st) { - if (*st == might_match) { - if (c == static_cast(toupper((*ky)[indx]))) { - consume = true; - if (ky->size() == indx + 1) { - *st = does_match; - --n_might_match; - ++n_does_match; - } - } else { - *st = doesnt_match; - --n_might_match; - } - } - } - // consume if we matched a character - if (consume) { - (void)is.get(); - // If we consumed a character and there might be a matched keyword that - // was marked matched on a previous iteration, then such keywords - // are now marked as not matching. - if (n_might_match + n_does_match > 1) { - st = status; - for (auto ky = kb; ky != ke; ++ky, ++st) { - if (*st == does_match && ky->size() != indx + 1) { - *st = doesnt_match; - --n_does_match; - } - } - } - } - } - // We've exited the loop because we hit eof and/or we have no more "might matches". - // Return the first matching result - for (st = status; kb != ke; ++kb, ++st) - if (*st == does_match) break; - if (kb == ke) is.setstate(std::ios::failbit); - return kb; -} - -} // namespace detail - -#endif // ONLY_C_LOCALE - -template -std::basic_ostream& to_stream(std::basic_ostream& os, const CharT* fmt, const fields& fds, const std::string* abbrev, - const std::chrono::seconds* offset_sec) { -#if ONLY_C_LOCALE - using detail::ampm_names; - using detail::month_names; - using detail::weekday_names; -#endif - using detail::extract_month; - using detail::extract_weekday; - using detail::get_units; - using detail::save_ostream; - using std::ios; - using std::chrono::duration_cast; - using std::chrono::hours; - using std::chrono::minutes; - using std::chrono::seconds; - date::detail::save_ostream ss(os); - os.fill(' '); - os.flags(std::ios::skipws | std::ios::dec); - os.width(0); - tm tm{}; - bool insert_negative = fds.has_tod && fds.tod.to_duration() < Duration::zero(); -#if !ONLY_C_LOCALE - auto& facet = std::use_facet>(os.getloc()); -#endif - const CharT* command = nullptr; - CharT modified = CharT{}; - for (; *fmt; ++fmt) { - switch (*fmt) { - case 'a': - case 'A': - if (command) { - if (modified == CharT{}) { - tm.tm_wday = static_cast(extract_weekday(os, fds)); - if (os.fail()) return os; -#if !ONLY_C_LOCALE - const CharT f[] = {'%', *fmt}; - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f)); -#else // ONLY_C_LOCALE - os << weekday_names().first[tm.tm_wday + 7 * (*fmt == 'a')]; -#endif // ONLY_C_LOCALE - } else { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } else - os << *fmt; - break; - case 'b': - case 'B': - case 'h': - if (command) { - if (modified == CharT{}) { - tm.tm_mon = static_cast(extract_month(os, fds)) - 1; -#if !ONLY_C_LOCALE - const CharT f[] = {'%', *fmt}; - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f)); -#else // ONLY_C_LOCALE - os << month_names().first[tm.tm_mon + 12 * (*fmt != 'B')]; -#endif // ONLY_C_LOCALE - } else { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } else - os << *fmt; - break; - case 'c': - case 'x': - if (command) { - if (modified == CharT{'O'}) - os << CharT{'%'} << modified << *fmt; - else { - if (!fds.ymd.ok()) os.setstate(std::ios::failbit); - if (*fmt == 'c' && !fds.has_tod) os.setstate(std::ios::failbit); -#if !ONLY_C_LOCALE - tm = std::tm{}; - auto const& ymd = fds.ymd; - auto ld = local_days(ymd); - if (*fmt == 'c') { - tm.tm_sec = static_cast(fds.tod.seconds().count()); - tm.tm_min = static_cast(fds.tod.minutes().count()); - tm.tm_hour = static_cast(fds.tod.hours().count()); - } - tm.tm_mday = static_cast(static_cast(ymd.day())); - tm.tm_mon = static_cast(extract_month(os, fds) - 1); - tm.tm_year = static_cast(ymd.year()) - 1900; - tm.tm_wday = static_cast(extract_weekday(os, fds)); - if (os.fail()) return os; - tm.tm_yday = static_cast((ld - local_days(ymd.year() / 1 / 1)).count()); - CharT f[3] = {'%'}; - auto fe = std::begin(f) + 1; - if (modified == CharT{'E'}) *fe++ = modified; - *fe++ = *fmt; - facet.put(os, os, os.fill(), &tm, std::begin(f), fe); -#else // ONLY_C_LOCALE - if (*fmt == 'c') { - auto wd = static_cast(extract_weekday(os, fds)); - os << weekday_names().first[static_cast(wd) + 7] << ' '; - os << month_names().first[extract_month(os, fds) - 1 + 12] << ' '; - auto d = static_cast(static_cast(fds.ymd.day())); - if (d < 10) os << ' '; - os << d << ' ' << make_time(duration_cast(fds.tod.to_duration())) << ' ' << fds.ymd.year(); - - } else // *fmt == 'x' - { - auto const& ymd = fds.ymd; - save_ostream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(2); - os << static_cast(ymd.month()) << CharT{'/'}; - os.width(2); - os << static_cast(ymd.day()) << CharT{'/'}; - os.width(2); - os << static_cast(ymd.year()) % 100; - } -#endif // ONLY_C_LOCALE - } - command = nullptr; - modified = CharT{}; - } else - os << *fmt; - break; - case 'C': - if (command) { - if (modified == CharT{'O'}) - os << CharT{'%'} << modified << *fmt; - else { - if (!fds.ymd.year().ok()) os.setstate(std::ios::failbit); - auto y = static_cast(fds.ymd.year()); -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#endif - { - save_ostream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - if (y >= 0) { - os.width(2); - os << y / 100; - } else { - os << CharT{'-'}; - os.width(2); - os << -(y - 99) / 100; - } - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'E'}) { - tm.tm_year = y - 1900; - CharT f[3] = {'%', 'E', 'C'}; - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f)); - } -#endif - } - command = nullptr; - modified = CharT{}; - } else - os << *fmt; - break; - case 'd': - case 'e': - if (command) { - if (modified == CharT{'E'}) - os << CharT{'%'} << modified << *fmt; - else { - if (!fds.ymd.day().ok()) os.setstate(std::ios::failbit); - auto d = static_cast(static_cast(fds.ymd.day())); -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#endif - { - save_ostream _(os); - if (*fmt == CharT{'d'}) - os.fill('0'); - else - os.fill(' '); - os.flags(std::ios::dec | std::ios::right); - os.width(2); - os << d; - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) { - tm.tm_mday = d; - CharT f[3] = {'%', 'O', *fmt}; - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f)); - } -#endif - } - command = nullptr; - modified = CharT{}; - } else - os << *fmt; - break; - case 'D': - if (command) { - if (modified == CharT{}) { - if (!fds.ymd.ok()) os.setstate(std::ios::failbit); - auto const& ymd = fds.ymd; - save_ostream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(2); - os << static_cast(ymd.month()) << CharT{'/'}; - os.width(2); - os << static_cast(ymd.day()) << CharT{'/'}; - os.width(2); - os << static_cast(ymd.year()) % 100; - } else { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } else - os << *fmt; - break; - case 'F': - if (command) { - if (modified == CharT{}) { - if (!fds.ymd.ok()) os.setstate(std::ios::failbit); - auto const& ymd = fds.ymd; - save_ostream _(os); - os.imbue(std::locale::classic()); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(4); - os << static_cast(ymd.year()) << CharT{'-'}; - os.width(2); - os << static_cast(ymd.month()) << CharT{'-'}; - os.width(2); - os << static_cast(ymd.day()); - } else { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } else - os << *fmt; - break; - case 'g': - case 'G': - if (command) { - if (modified == CharT{}) { - if (!fds.ymd.ok()) os.setstate(std::ios::failbit); - auto ld = local_days(fds.ymd); - auto y = year_month_day{ld + days{3}}.year(); - auto start = local_days((y - years{1}) / December / Thursday[last]) + (Monday - Thursday); - if (ld < start) --y; - if (*fmt == CharT{'G'}) - os << y; - else { - save_ostream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(2); - os << std::abs(static_cast(y)) % 100; - } - } else { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } else - os << *fmt; - break; - case 'H': - case 'I': - if (command) { - if (modified == CharT{'E'}) - os << CharT{'%'} << modified << *fmt; - else { - if (!fds.has_tod) os.setstate(std::ios::failbit); - if (insert_negative) { - os << '-'; - insert_negative = false; - } - auto hms = fds.tod; -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#endif - { - auto h = *fmt == CharT{'I'} ? date::make12(hms.hours()) : hms.hours(); - if (h < hours{10}) os << CharT{'0'}; - os << h.count(); - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_hour = static_cast(hms.hours().count()); - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f)); - } -#endif - } - modified = CharT{}; - command = nullptr; - } else - os << *fmt; - break; - case 'j': - if (command) { - if (modified == CharT{}) { - if (fds.ymd.ok() || fds.has_tod) { - days doy; - if (fds.ymd.ok()) { - auto ld = local_days(fds.ymd); - auto y = fds.ymd.year(); - doy = ld - local_days(y / January / 1) + days{1}; - } else { - doy = duration_cast(fds.tod.to_duration()); - } - save_ostream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(3); - os << doy.count(); - } else { - os.setstate(std::ios::failbit); - } - } else { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } else - os << *fmt; - break; - case 'm': - if (command) { - if (modified == CharT{'E'}) - os << CharT{'%'} << modified << *fmt; - else { - if (!fds.ymd.month().ok()) os.setstate(std::ios::failbit); - auto m = static_cast(fds.ymd.month()); -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#endif - { - if (m < 10) os << CharT{'0'}; - os << m; - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_mon = static_cast(m - 1); - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f)); - } -#endif - } - modified = CharT{}; - command = nullptr; - } else - os << *fmt; - break; - case 'M': - if (command) { - if (modified == CharT{'E'}) - os << CharT{'%'} << modified << *fmt; - else { - if (!fds.has_tod) os.setstate(std::ios::failbit); - if (insert_negative) { - os << '-'; - insert_negative = false; - } -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#endif - { - if (fds.tod.minutes() < minutes{10}) os << CharT{'0'}; - os << fds.tod.minutes().count(); - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_min = static_cast(fds.tod.minutes().count()); - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f)); - } -#endif - } - modified = CharT{}; - command = nullptr; - } else - os << *fmt; - break; - case 'n': - if (command) { - if (modified == CharT{}) - os << CharT{'\n'}; - else { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } else - os << *fmt; - break; - case 'p': - if (command) { - if (modified == CharT{}) { - if (!fds.has_tod) os.setstate(std::ios::failbit); -#if !ONLY_C_LOCALE - const CharT f[] = {'%', *fmt}; - tm.tm_hour = static_cast(fds.tod.hours().count()); - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f)); -#else - if (date::is_am(fds.tod.hours())) - os << ampm_names().first[0]; - else - os << ampm_names().first[1]; -#endif - } else { - os << CharT{'%'} << modified << *fmt; - } - modified = CharT{}; - command = nullptr; - } else - os << *fmt; - break; - case 'Q': - case 'q': - if (command) { - if (modified == CharT{}) { - if (!fds.has_tod) os.setstate(std::ios::failbit); - auto d = fds.tod.to_duration(); - if (*fmt == 'q') - os << get_units(typename decltype(d)::period::type{}); - else - os << d.count(); - } else { - os << CharT{'%'} << modified << *fmt; - } - modified = CharT{}; - command = nullptr; - } else - os << *fmt; - break; - case 'r': - if (command) { - if (modified == CharT{}) { - if (!fds.has_tod) os.setstate(std::ios::failbit); -#if !ONLY_C_LOCALE - const CharT f[] = {'%', *fmt}; - tm.tm_hour = static_cast(fds.tod.hours().count()); - tm.tm_min = static_cast(fds.tod.minutes().count()); - tm.tm_sec = static_cast(fds.tod.seconds().count()); - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f)); -#else - hh_mm_ss tod(duration_cast(fds.tod.to_duration())); - save_ostream _(os); - os.fill('0'); - os.width(2); - os << date::make12(tod.hours()).count() << CharT{':'}; - os.width(2); - os << tod.minutes().count() << CharT{':'}; - os.width(2); - os << tod.seconds().count() << CharT{' '}; - if (date::is_am(tod.hours())) - os << ampm_names().first[0]; - else - os << ampm_names().first[1]; -#endif - } else { - os << CharT{'%'} << modified << *fmt; - } - modified = CharT{}; - command = nullptr; - } else - os << *fmt; - break; - case 'R': - if (command) { - if (modified == CharT{}) { - if (!fds.has_tod) os.setstate(std::ios::failbit); - if (fds.tod.hours() < hours{10}) os << CharT{'0'}; - os << fds.tod.hours().count() << CharT{':'}; - if (fds.tod.minutes() < minutes{10}) os << CharT{'0'}; - os << fds.tod.minutes().count(); - } else { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } else - os << *fmt; - break; - case 'S': - if (command) { - if (modified == CharT{'E'}) - os << CharT{'%'} << modified << *fmt; - else { - if (!fds.has_tod) os.setstate(std::ios::failbit); - if (insert_negative) { - os << '-'; - insert_negative = false; - } -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#endif - { - os << fds.tod.s_; - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_sec = static_cast(fds.tod.s_.seconds().count()); - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f)); - } -#endif - } - modified = CharT{}; - command = nullptr; - } else - os << *fmt; - break; - case 't': - if (command) { - if (modified == CharT{}) - os << CharT{'\t'}; - else { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } else - os << *fmt; - break; - case 'T': - if (command) { - if (modified == CharT{}) { - if (!fds.has_tod) os.setstate(std::ios::failbit); - os << fds.tod; - } else { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } else - os << *fmt; - break; - case 'u': - if (command) { - if (modified == CharT{'E'}) - os << CharT{'%'} << modified << *fmt; - else { - auto wd = extract_weekday(os, fds); -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#endif - { - os << (wd != 0 ? wd : 7u); - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_wday = static_cast(wd); - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f)); - } -#endif - } - modified = CharT{}; - command = nullptr; - } else - os << *fmt; - break; - case 'U': - if (command) { - if (modified == CharT{'E'}) - os << CharT{'%'} << modified << *fmt; - else { - auto const& ymd = fds.ymd; - if (!ymd.ok()) os.setstate(std::ios::failbit); - auto ld = local_days(ymd); -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#endif - { - auto st = local_days(Sunday[1] / January / ymd.year()); - if (ld < st) - os << CharT{'0'} << CharT{'0'}; - else { - auto wn = duration_cast(ld - st).count() + 1; - if (wn < 10) os << CharT{'0'}; - os << wn; - } - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_year = static_cast(ymd.year()) - 1900; - tm.tm_wday = static_cast(extract_weekday(os, fds)); - if (os.fail()) return os; - tm.tm_yday = static_cast((ld - local_days(ymd.year() / 1 / 1)).count()); - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f)); - } -#endif - } - modified = CharT{}; - command = nullptr; - } else - os << *fmt; - break; - case 'V': - if (command) { - if (modified == CharT{'E'}) - os << CharT{'%'} << modified << *fmt; - else { - if (!fds.ymd.ok()) os.setstate(std::ios::failbit); - auto ld = local_days(fds.ymd); -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#endif - { - auto y = year_month_day{ld + days{3}}.year(); - auto st = local_days((y - years{1}) / 12 / Thursday[last]) + (Monday - Thursday); - if (ld < st) { - --y; - st = local_days((y - years{1}) / 12 / Thursday[last]) + (Monday - Thursday); - } - auto wn = duration_cast(ld - st).count() + 1; - if (wn < 10) os << CharT{'0'}; - os << wn; - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) { - const CharT f[] = {'%', modified, *fmt}; - auto const& ymd = fds.ymd; - tm.tm_year = static_cast(ymd.year()) - 1900; - tm.tm_wday = static_cast(extract_weekday(os, fds)); - if (os.fail()) return os; - tm.tm_yday = static_cast((ld - local_days(ymd.year() / 1 / 1)).count()); - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f)); - } -#endif - } - modified = CharT{}; - command = nullptr; - } else - os << *fmt; - break; - case 'w': - if (command) { - auto wd = extract_weekday(os, fds); - if (os.fail()) return os; -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#else - if (modified != CharT{'E'}) -#endif - { - os << wd; - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_wday = static_cast(wd); - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f)); - } -#endif - else { - os << CharT{'%'} << modified << *fmt; - } - modified = CharT{}; - command = nullptr; - } else - os << *fmt; - break; - case 'W': - if (command) { - if (modified == CharT{'E'}) - os << CharT{'%'} << modified << *fmt; - else { - auto const& ymd = fds.ymd; - if (!ymd.ok()) os.setstate(std::ios::failbit); - auto ld = local_days(ymd); -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#endif - { - auto st = local_days(Monday[1] / January / ymd.year()); - if (ld < st) - os << CharT{'0'} << CharT{'0'}; - else { - auto wn = duration_cast(ld - st).count() + 1; - if (wn < 10) os << CharT{'0'}; - os << wn; - } - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_year = static_cast(ymd.year()) - 1900; - tm.tm_wday = static_cast(extract_weekday(os, fds)); - if (os.fail()) return os; - tm.tm_yday = static_cast((ld - local_days(ymd.year() / 1 / 1)).count()); - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f)); - } -#endif - } - modified = CharT{}; - command = nullptr; - } else - os << *fmt; - break; - case 'X': - if (command) { - if (modified == CharT{'O'}) - os << CharT{'%'} << modified << *fmt; - else { - if (!fds.has_tod) os.setstate(std::ios::failbit); -#if !ONLY_C_LOCALE - tm = std::tm{}; - tm.tm_sec = static_cast(fds.tod.seconds().count()); - tm.tm_min = static_cast(fds.tod.minutes().count()); - tm.tm_hour = static_cast(fds.tod.hours().count()); - CharT f[3] = {'%'}; - auto fe = std::begin(f) + 1; - if (modified == CharT{'E'}) *fe++ = modified; - *fe++ = *fmt; - facet.put(os, os, os.fill(), &tm, std::begin(f), fe); -#else - os << fds.tod; -#endif - } - command = nullptr; - modified = CharT{}; - } else - os << *fmt; - break; - case 'y': - if (command) { - if (!fds.ymd.year().ok()) os.setstate(std::ios::failbit); - auto y = static_cast(fds.ymd.year()); -#if !ONLY_C_LOCALE - if (modified == CharT{}) { -#endif - y = std::abs(y) % 100; - if (y < 10) os << CharT{'0'}; - os << y; -#if !ONLY_C_LOCALE - } else { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_year = y - 1900; - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f)); - } -#endif - modified = CharT{}; - command = nullptr; - } else - os << *fmt; - break; - case 'Y': - if (command) { - if (modified == CharT{'O'}) - os << CharT{'%'} << modified << *fmt; - else { - if (!fds.ymd.year().ok()) os.setstate(std::ios::failbit); - auto y = fds.ymd.year(); -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#endif - { - save_ostream _(os); - os.imbue(std::locale::classic()); - os << y; - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'E'}) { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_year = static_cast(y) - 1900; - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f)); - } -#endif - } - modified = CharT{}; - command = nullptr; - } else - os << *fmt; - break; - case 'z': - if (command) { - if (offset_sec == nullptr) { - // Can not format %z with unknown offset - os.setstate(ios::failbit); - return os; - } - auto m = duration_cast(*offset_sec); - auto neg = m < minutes{0}; - m = date::abs(m); - auto h = duration_cast(m); - m -= h; - if (neg) - os << CharT{'-'}; - else - os << CharT{'+'}; - if (h < hours{10}) os << CharT{'0'}; - os << h.count(); - if (modified != CharT{}) os << CharT{':'}; - if (m < minutes{10}) os << CharT{'0'}; - os << m.count(); - command = nullptr; - modified = CharT{}; - } else - os << *fmt; - break; - case 'Z': - if (command) { - if (modified == CharT{}) { - if (abbrev == nullptr) { - // Can not format %Z with unknown time_zone - os.setstate(ios::failbit); - return os; - } - for (auto c : *abbrev) os << CharT(c); - } else { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } else - os << *fmt; - break; - case 'E': - case 'O': - if (command) { - if (modified == CharT{}) { - modified = *fmt; - } else { - os << CharT{'%'} << modified << *fmt; - command = nullptr; - modified = CharT{}; - } - } else - os << *fmt; - break; - case '%': - if (command) { - if (modified == CharT{}) { - os << CharT{'%'}; - command = nullptr; - } else { - os << CharT{'%'} << modified << CharT{'%'}; - command = nullptr; - modified = CharT{}; - } - } else - command = fmt; - break; - default: - if (command) { - os << CharT{'%'}; - command = nullptr; - } - if (modified != CharT{}) { - os << modified; - modified = CharT{}; - } - os << *fmt; - break; - } - } - if (command) os << CharT{'%'}; - if (modified != CharT{}) os << modified; - return os; -} - -template -inline std::basic_ostream& to_stream(std::basic_ostream& os, const CharT* fmt, const year& y) { - using CT = std::chrono::seconds; - fields fds{y / 0 / 0}; - return to_stream(os, fmt, fds); -} - -template -inline std::basic_ostream& to_stream(std::basic_ostream& os, const CharT* fmt, const month& m) { - using CT = std::chrono::seconds; - fields fds{m / 0 / nanyear}; - return to_stream(os, fmt, fds); -} - -template -inline std::basic_ostream& to_stream(std::basic_ostream& os, const CharT* fmt, const day& d) { - using CT = std::chrono::seconds; - fields fds{d / 0 / nanyear}; - return to_stream(os, fmt, fds); -} - -template -inline std::basic_ostream& to_stream(std::basic_ostream& os, const CharT* fmt, const weekday& wd) { - using CT = std::chrono::seconds; - fields fds{wd}; - return to_stream(os, fmt, fds); -} - -template -inline std::basic_ostream& to_stream(std::basic_ostream& os, const CharT* fmt, const year_month& ym) { - using CT = std::chrono::seconds; - fields fds{ym / 0}; - return to_stream(os, fmt, fds); -} - -template -inline std::basic_ostream& to_stream(std::basic_ostream& os, const CharT* fmt, const month_day& md) { - using CT = std::chrono::seconds; - fields fds{md / nanyear}; - return to_stream(os, fmt, fds); -} - -template -inline std::basic_ostream& to_stream(std::basic_ostream& os, const CharT* fmt, const year_month_day& ymd) { - using CT = std::chrono::seconds; - fields fds{ymd}; - return to_stream(os, fmt, fds); -} - -template -inline std::basic_ostream& to_stream(std::basic_ostream& os, const CharT* fmt, const std::chrono::duration& d) { - using Duration = std::chrono::duration; - using CT = typename std::common_type::type; - fields fds{hh_mm_ss{d}}; - return to_stream(os, fmt, fds); -} - -template -std::basic_ostream& to_stream(std::basic_ostream& os, const CharT* fmt, const local_time& tp, - const std::string* abbrev = nullptr, const std::chrono::seconds* offset_sec = nullptr) { - using CT = typename std::common_type::type; - auto ld = floor(tp); - fields fds{year_month_day{ld}, hh_mm_ss{tp - local_seconds{ld}}}; - return to_stream(os, fmt, fds, abbrev, offset_sec); -} - -template -std::basic_ostream& to_stream(std::basic_ostream& os, const CharT* fmt, const sys_time& tp) { - using std::chrono::seconds; - using CT = typename std::common_type::type; - const std::string abbrev("UTC"); - CONSTDATA seconds offset{0}; - auto sd = floor(tp); - fields fds{year_month_day{sd}, hh_mm_ss{tp - sys_seconds{sd}}}; - return to_stream(os, fmt, fds, &abbrev, &offset); -} - -// format - -template -auto format(const std::locale& loc, const CharT* fmt, const Streamable& tp) - -> decltype(to_stream(std::declval&>(), fmt, tp), std::basic_string{}) { - std::basic_ostringstream os; - os.exceptions(std::ios::failbit | std::ios::badbit); - os.imbue(loc); - to_stream(os, fmt, tp); - return os.str(); -} - -template -auto format(const CharT* fmt, const Streamable& tp) -> decltype(to_stream(std::declval&>(), fmt, tp), std::basic_string{}) { - std::basic_ostringstream os; - os.exceptions(std::ios::failbit | std::ios::badbit); - to_stream(os, fmt, tp); - return os.str(); -} - -template -auto format(const std::locale& loc, const std::basic_string& fmt, const Streamable& tp) - -> decltype(to_stream(std::declval&>(), fmt.c_str(), tp), std::basic_string{}) { - std::basic_ostringstream os; - os.exceptions(std::ios::failbit | std::ios::badbit); - os.imbue(loc); - to_stream(os, fmt.c_str(), tp); - return os.str(); -} - -template -auto format(const std::basic_string& fmt, const Streamable& tp) - -> decltype(to_stream(std::declval&>(), fmt.c_str(), tp), std::basic_string{}) { - std::basic_ostringstream os; - os.exceptions(std::ios::failbit | std::ios::badbit); - to_stream(os, fmt.c_str(), tp); - return os.str(); -} - -// parse - -namespace detail { - -template -bool read_char(std::basic_istream& is, CharT fmt, std::ios::iostate& err) { - auto ic = is.get(); - if (Traits::eq_int_type(ic, Traits::eof()) || !Traits::eq(Traits::to_char_type(ic), fmt)) { - err |= std::ios::failbit; - is.setstate(std::ios::failbit); - return false; - } - return true; -} - -template -unsigned read_unsigned(std::basic_istream& is, unsigned m = 1, unsigned M = 10) { - unsigned x = 0; - unsigned count = 0; - while (true) { - auto ic = is.peek(); - if (Traits::eq_int_type(ic, Traits::eof())) break; - auto c = static_cast(Traits::to_char_type(ic)); - if (!('0' <= c && c <= '9')) break; - (void)is.get(); - ++count; - x = 10 * x + static_cast(c - '0'); - if (count == M) break; - } - if (count < m) is.setstate(std::ios::failbit); - return x; -} - -template -int read_signed(std::basic_istream& is, unsigned m = 1, unsigned M = 10) { - auto ic = is.peek(); - if (!Traits::eq_int_type(ic, Traits::eof())) { - auto c = static_cast(Traits::to_char_type(ic)); - if (('0' <= c && c <= '9') || c == '-' || c == '+') { - if (c == '-' || c == '+') (void)is.get(); - auto x = static_cast(read_unsigned(is, std::max(m, 1u), M)); - if (!is.fail()) { - if (c == '-') x = -x; - return x; - } - } - } - if (m > 0) is.setstate(std::ios::failbit); - return 0; -} - -template -long double read_long_double(std::basic_istream& is, unsigned m = 1, unsigned M = 10) { - unsigned count = 0; - auto decimal_point = Traits::to_int_type(std::use_facet>(is.getloc()).decimal_point()); - std::string buf; - while (true) { - auto ic = is.peek(); - if (Traits::eq_int_type(ic, Traits::eof())) break; - if (Traits::eq_int_type(ic, decimal_point)) { - buf += '.'; - decimal_point = Traits::eof(); - is.get(); - } else { - auto c = static_cast(Traits::to_char_type(ic)); - if (!('0' <= c && c <= '9')) break; - buf += c; - (void)is.get(); - } - if (++count == M) break; - } - if (count < m) { - is.setstate(std::ios::failbit); - return 0; - } - return std::stold(buf); -} - -struct rs { - int& i; - unsigned m; - unsigned M; -}; - -struct ru { - int& i; - unsigned m; - unsigned M; -}; - -struct rld { - long double& i; - unsigned m; - unsigned M; -}; - -template -void read(std::basic_istream&) {} - -template -void read(std::basic_istream& is, CharT a0, Args&&... args); - -template -void read(std::basic_istream& is, rs a0, Args&&... args); - -template -void read(std::basic_istream& is, ru a0, Args&&... args); - -template -void read(std::basic_istream& is, int a0, Args&&... args); - -template -void read(std::basic_istream& is, rld a0, Args&&... args); - -template -void read(std::basic_istream& is, CharT a0, Args&&... args) { - // No-op if a0 == CharT{} - if (a0 != CharT{}) { - auto ic = is.peek(); - if (Traits::eq_int_type(ic, Traits::eof())) { - is.setstate(std::ios::failbit | std::ios::eofbit); - return; - } - if (!Traits::eq(Traits::to_char_type(ic), a0)) { - is.setstate(std::ios::failbit); - return; - } - (void)is.get(); - } - read(is, std::forward(args)...); -} - -template -void read(std::basic_istream& is, rs a0, Args&&... args) { - auto x = read_signed(is, a0.m, a0.M); - if (is.fail()) return; - a0.i = x; - read(is, std::forward(args)...); -} - -template -void read(std::basic_istream& is, ru a0, Args&&... args) { - auto x = read_unsigned(is, a0.m, a0.M); - if (is.fail()) return; - a0.i = static_cast(x); - read(is, std::forward(args)...); -} - -template -void read(std::basic_istream& is, int a0, Args&&... args) { - if (a0 != -1) { - auto u = static_cast(a0); - CharT buf[std::numeric_limits::digits10 + 2u] = {}; - auto e = buf; - do { - *e++ = static_cast(CharT(u % 10) + CharT{'0'}); - u /= 10; - } while (u > 0); - std::reverse(buf, e); - for (auto p = buf; p != e && is.rdstate() == std::ios::goodbit; ++p) read(is, *p); - } - if (is.rdstate() == std::ios::goodbit) read(is, std::forward(args)...); -} - -template -void read(std::basic_istream& is, rld a0, Args&&... args) { - auto x = read_long_double(is, a0.m, a0.M); - if (is.fail()) return; - a0.i = x; - read(is, std::forward(args)...); -} - -template -inline void checked_set(T& value, T from, T not_a_value, std::basic_ios& is) { - if (!is.fail()) { - if (value == not_a_value) - value = std::move(from); - else if (value != from) - is.setstate(std::ios::failbit); - } -} - -} // namespace detail - -template > -std::basic_istream& from_stream(std::basic_istream& is, const CharT* fmt, fields& fds, - std::basic_string* abbrev, std::chrono::minutes* offset) { - using std::ios; - using std::numeric_limits; - using std::chrono::duration; - using std::chrono::duration_cast; - using std::chrono::hours; - using std::chrono::minutes; - using std::chrono::seconds; - typename std::basic_istream::sentry ok{is, true}; - if (ok) { - date::detail::save_istream ss(is); - is.fill(' '); - is.flags(std::ios::skipws | std::ios::dec); - is.width(0); -#if !ONLY_C_LOCALE - auto& f = std::use_facet>(is.getloc()); - std::tm tm{}; -#endif - const CharT* command = nullptr; - auto modified = CharT{}; - auto width = -1; - - CONSTDATA int not_a_year = numeric_limits::min(); - CONSTDATA int not_a_2digit_year = 100; - CONSTDATA int not_a_century = not_a_year / 100; - CONSTDATA int not_a_month = 0; - CONSTDATA int not_a_day = 0; - CONSTDATA int not_a_hour = numeric_limits::min(); - CONSTDATA int not_a_hour_12_value = 0; - CONSTDATA int not_a_minute = not_a_hour; - CONSTDATA Duration not_a_second = Duration::min(); - CONSTDATA int not_a_doy = -1; - CONSTDATA int not_a_weekday = 8; - CONSTDATA int not_a_week_num = 100; - CONSTDATA int not_a_ampm = -1; - CONSTDATA minutes not_a_offset = minutes::min(); - - int Y = not_a_year; // c, F, Y * - int y = not_a_2digit_year; // D, x, y * - int g = not_a_2digit_year; // g * - int G = not_a_year; // G * - int C = not_a_century; // C * - int m = not_a_month; // b, B, h, m, c, D, F, x * - int d = not_a_day; // c, d, D, e, F, x * - int j = not_a_doy; // j * - int wd = not_a_weekday; // a, A, u, w * - int H = not_a_hour; // c, H, R, T, X * - int I = not_a_hour_12_value; // I, r * - int p = not_a_ampm; // p, r * - int M = not_a_minute; // c, M, r, R, T, X * - Duration s = not_a_second; // c, r, S, T, X * - int U = not_a_week_num; // U * - int V = not_a_week_num; // V * - int W = not_a_week_num; // W * - std::basic_string temp_abbrev; // Z * - minutes temp_offset = not_a_offset; // z * - - using detail::checked_set; - using detail::read; - using detail::rld; - using detail::rs; - using detail::ru; - for (; *fmt != CharT{} && !is.fail(); ++fmt) { - switch (*fmt) { - case 'a': - case 'A': - case 'u': - case 'w': // wd: a, A, u, w - if (command) { - int trial_wd = not_a_weekday; - if (*fmt == 'a' || *fmt == 'A') { - if (modified == CharT{}) { -#if !ONLY_C_LOCALE - ios::iostate err = ios::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt + 1); - is.setstate(err); - if (!is.fail()) trial_wd = tm.tm_wday; -#else - auto nm = detail::weekday_names(); - auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first; - if (!is.fail()) trial_wd = i % 7; -#endif - } else - read(is, CharT{'%'}, width, modified, *fmt); - } else // *fmt == 'u' || *fmt == 'w' - { -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#else - if (modified != CharT{'E'}) -#endif - { - read(is, ru{trial_wd, 1, width == -1 ? 1u : static_cast(width)}); - if (!is.fail()) { - if (*fmt == 'u') { - if (!(1 <= trial_wd && trial_wd <= 7)) { - trial_wd = not_a_weekday; - is.setstate(ios::failbit); - } else if (trial_wd == 7) - trial_wd = 0; - } else // *fmt == 'w' - { - if (!(0 <= trial_wd && trial_wd <= 6)) { - trial_wd = not_a_weekday; - is.setstate(ios::failbit); - } - } - } - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) { - ios::iostate err = ios::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt + 1); - is.setstate(err); - if (!is.fail()) trial_wd = tm.tm_wday; - } -#endif - else - read(is, CharT{'%'}, width, modified, *fmt); - } - if (trial_wd != not_a_weekday) checked_set(wd, trial_wd, not_a_weekday, is); - } else // !command - read(is, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - break; - case 'b': - case 'B': - case 'h': - if (command) { - if (modified == CharT{}) { - int ttm = not_a_month; -#if !ONLY_C_LOCALE - ios::iostate err = ios::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt + 1); - if ((err & ios::failbit) == 0) ttm = tm.tm_mon + 1; - is.setstate(err); -#else - auto nm = detail::month_names(); - auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first; - if (!is.fail()) ttm = i % 12 + 1; -#endif - checked_set(m, ttm, not_a_month, is); - } else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } else - read(is, *fmt); - break; - case 'c': - if (command) { - if (modified != CharT{'O'}) { -#if !ONLY_C_LOCALE - ios::iostate err = ios::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt + 1); - if ((err & ios::failbit) == 0) { - checked_set(Y, tm.tm_year + 1900, not_a_year, is); - checked_set(m, tm.tm_mon + 1, not_a_month, is); - checked_set(d, tm.tm_mday, not_a_day, is); - checked_set(H, tm.tm_hour, not_a_hour, is); - checked_set(M, tm.tm_min, not_a_minute, is); - checked_set(s, duration_cast(seconds{tm.tm_sec}), not_a_second, is); - } - is.setstate(err); -#else - // "%a %b %e %T %Y" - auto nm = detail::weekday_names(); - auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first; - checked_set(wd, static_cast(i % 7), not_a_weekday, is); - ws(is); - nm = detail::month_names(); - i = detail::scan_keyword(is, nm.first, nm.second) - nm.first; - checked_set(m, static_cast(i % 12 + 1), not_a_month, is); - ws(is); - int td = not_a_day; - read(is, rs{td, 1, 2}); - checked_set(d, td, not_a_day, is); - ws(is); - using dfs = detail::decimal_format_seconds; - CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width; - int tH; - int tM; - long double S; - read(is, ru{tH, 1, 2}, CharT{':'}, ru{tM, 1, 2}, CharT{':'}, rld{S, 1, w}); - checked_set(H, tH, not_a_hour, is); - checked_set(M, tM, not_a_minute, is); - checked_set(s, round(duration{S}), not_a_second, is); - ws(is); - int tY = not_a_year; - read(is, rs{tY, 1, 4u}); - checked_set(Y, tY, not_a_year, is); -#endif - } else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } else - read(is, *fmt); - break; - case 'x': - if (command) { - if (modified != CharT{'O'}) { -#if !ONLY_C_LOCALE - ios::iostate err = ios::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt + 1); - if ((err & ios::failbit) == 0) { - checked_set(Y, tm.tm_year + 1900, not_a_year, is); - checked_set(m, tm.tm_mon + 1, not_a_month, is); - checked_set(d, tm.tm_mday, not_a_day, is); - } - is.setstate(err); -#else - // "%m/%d/%y" - int ty = not_a_2digit_year; - int tm = not_a_month; - int td = not_a_day; - read(is, ru{tm, 1, 2}, CharT{'/'}, ru{td, 1, 2}, CharT{'/'}, rs{ty, 1, 2}); - checked_set(y, ty, not_a_2digit_year, is); - checked_set(m, tm, not_a_month, is); - checked_set(d, td, not_a_day, is); -#endif - } else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } else - read(is, *fmt); - break; - case 'X': - if (command) { - if (modified != CharT{'O'}) { -#if !ONLY_C_LOCALE - ios::iostate err = ios::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt + 1); - if ((err & ios::failbit) == 0) { - checked_set(H, tm.tm_hour, not_a_hour, is); - checked_set(M, tm.tm_min, not_a_minute, is); - checked_set(s, duration_cast(seconds{tm.tm_sec}), not_a_second, is); - } - is.setstate(err); -#else - // "%T" - using dfs = detail::decimal_format_seconds; - CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width; - int tH = not_a_hour; - int tM = not_a_minute; - long double S; - read(is, ru{tH, 1, 2}, CharT{':'}, ru{tM, 1, 2}, CharT{':'}, rld{S, 1, w}); - checked_set(H, tH, not_a_hour, is); - checked_set(M, tM, not_a_minute, is); - checked_set(s, round(duration{S}), not_a_second, is); -#endif - } else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } else - read(is, *fmt); - break; - case 'C': - if (command) { - int tC = not_a_century; -#if !ONLY_C_LOCALE - if (modified == CharT{}) { -#endif - read(is, rs{tC, 1, width == -1 ? 2u : static_cast(width)}); -#if !ONLY_C_LOCALE - } else { - ios::iostate err = ios::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt + 1); - if ((err & ios::failbit) == 0) { - auto tY = tm.tm_year + 1900; - tC = (tY >= 0 ? tY : tY - 99) / 100; - } - is.setstate(err); - } -#endif - checked_set(C, tC, not_a_century, is); - command = nullptr; - width = -1; - modified = CharT{}; - } else - read(is, *fmt); - break; - case 'D': - if (command) { - if (modified == CharT{}) { - int tn = not_a_month; - int td = not_a_day; - int ty = not_a_2digit_year; - read(is, ru{tn, 1, 2}, CharT{'\0'}, CharT{'/'}, CharT{'\0'}, ru{td, 1, 2}, CharT{'\0'}, CharT{'/'}, CharT{'\0'}, rs{ty, 1, 2}); - checked_set(y, ty, not_a_2digit_year, is); - checked_set(m, tn, not_a_month, is); - checked_set(d, td, not_a_day, is); - } else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } else - read(is, *fmt); - break; - case 'F': - if (command) { - if (modified == CharT{}) { - int tY = not_a_year; - int tn = not_a_month; - int td = not_a_day; - read(is, rs{tY, 1, width == -1 ? 4u : static_cast(width)}, CharT{'-'}, ru{tn, 1, 2}, CharT{'-'}, ru{td, 1, 2}); - checked_set(Y, tY, not_a_year, is); - checked_set(m, tn, not_a_month, is); - checked_set(d, td, not_a_day, is); - } else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } else - read(is, *fmt); - break; - case 'd': - case 'e': - if (command) { -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#else - if (modified != CharT{'E'}) -#endif - { - int td = not_a_day; - read(is, rs{td, 1, width == -1 ? 2u : static_cast(width)}); - checked_set(d, td, not_a_day, is); - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) { - ios::iostate err = ios::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt + 1); - command = nullptr; - width = -1; - modified = CharT{}; - if ((err & ios::failbit) == 0) checked_set(d, tm.tm_mday, not_a_day, is); - is.setstate(err); - } -#endif - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } else - read(is, *fmt); - break; - case 'H': - if (command) { -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#else - if (modified != CharT{'E'}) -#endif - { - int tH = not_a_hour; - read(is, ru{tH, 1, width == -1 ? 2u : static_cast(width)}); - checked_set(H, tH, not_a_hour, is); - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) { - ios::iostate err = ios::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt + 1); - if ((err & ios::failbit) == 0) checked_set(H, tm.tm_hour, not_a_hour, is); - is.setstate(err); - } -#endif - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } else - read(is, *fmt); - break; - case 'I': - if (command) { - if (modified == CharT{}) { - int tI = not_a_hour_12_value; - // reads in an hour into I, but most be in [1, 12] - read(is, rs{tI, 1, width == -1 ? 2u : static_cast(width)}); - if (!(1 <= tI && tI <= 12)) is.setstate(ios::failbit); - checked_set(I, tI, not_a_hour_12_value, is); - } else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } else - read(is, *fmt); - break; - case 'j': - if (command) { - if (modified == CharT{}) { - int tj = not_a_doy; - read(is, ru{tj, 1, width == -1 ? 3u : static_cast(width)}); - checked_set(j, tj, not_a_doy, is); - } else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } else - read(is, *fmt); - break; - case 'M': - if (command) { -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#else - if (modified != CharT{'E'}) -#endif - { - int tM = not_a_minute; - read(is, ru{tM, 1, width == -1 ? 2u : static_cast(width)}); - checked_set(M, tM, not_a_minute, is); - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) { - ios::iostate err = ios::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt + 1); - if ((err & ios::failbit) == 0) checked_set(M, tm.tm_min, not_a_minute, is); - is.setstate(err); - } -#endif - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } else - read(is, *fmt); - break; - case 'm': - if (command) { -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#else - if (modified != CharT{'E'}) -#endif - { - int tn = not_a_month; - read(is, rs{tn, 1, width == -1 ? 2u : static_cast(width)}); - checked_set(m, tn, not_a_month, is); - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) { - ios::iostate err = ios::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt + 1); - if ((err & ios::failbit) == 0) checked_set(m, tm.tm_mon + 1, not_a_month, is); - is.setstate(err); - } -#endif - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } else - read(is, *fmt); - break; - case 'n': - case 't': - if (command) { - if (modified == CharT{}) { - // %n matches a single white space character - // %t matches 0 or 1 white space characters - auto ic = is.peek(); - if (Traits::eq_int_type(ic, Traits::eof())) { - ios::iostate err = ios::eofbit; - if (*fmt == 'n') err |= ios::failbit; - is.setstate(err); - break; - } - if (isspace(ic)) { - (void)is.get(); - } else if (*fmt == 'n') - is.setstate(ios::failbit); - } else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } else - read(is, *fmt); - break; - case 'p': - if (command) { - if (modified == CharT{}) { - int tp = not_a_ampm; -#if !ONLY_C_LOCALE - tm = std::tm{}; - tm.tm_hour = 1; - ios::iostate err = ios::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt + 1); - is.setstate(err); - if (tm.tm_hour == 1) - tp = 0; - else if (tm.tm_hour == 13) - tp = 1; - else - is.setstate(err); -#else - auto nm = detail::ampm_names(); - auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first; - tp = i; -#endif - checked_set(p, tp, not_a_ampm, is); - } else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } else - read(is, *fmt); - - break; - case 'r': - if (command) { - if (modified == CharT{}) { -#if !ONLY_C_LOCALE - ios::iostate err = ios::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt + 1); - if ((err & ios::failbit) == 0) { - checked_set(H, tm.tm_hour, not_a_hour, is); - checked_set(M, tm.tm_min, not_a_hour, is); - checked_set(s, duration_cast(seconds{tm.tm_sec}), not_a_second, is); - } - is.setstate(err); -#else - // "%I:%M:%S %p" - using dfs = detail::decimal_format_seconds; - CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width; - long double S; - int tI = not_a_hour_12_value; - int tM = not_a_minute; - read(is, ru{tI, 1, 2}, CharT{':'}, ru{tM, 1, 2}, CharT{':'}, rld{S, 1, w}); - checked_set(I, tI, not_a_hour_12_value, is); - checked_set(M, tM, not_a_minute, is); - checked_set(s, round(duration{S}), not_a_second, is); - ws(is); - auto nm = detail::ampm_names(); - auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first; - checked_set(p, static_cast(i), not_a_ampm, is); -#endif - } else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } else - read(is, *fmt); - break; - case 'R': - if (command) { - if (modified == CharT{}) { - int tH = not_a_hour; - int tM = not_a_minute; - read(is, ru{tH, 1, 2}, CharT{'\0'}, CharT{':'}, CharT{'\0'}, ru{tM, 1, 2}, CharT{'\0'}); - checked_set(H, tH, not_a_hour, is); - checked_set(M, tM, not_a_minute, is); - } else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } else - read(is, *fmt); - break; - case 'S': - if (command) { -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#else - if (modified != CharT{'E'}) -#endif - { - using dfs = detail::decimal_format_seconds; - CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width; - long double S; - read(is, rld{S, 1, width == -1 ? w : static_cast(width)}); - checked_set(s, round(duration{S}), not_a_second, is); - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) { - ios::iostate err = ios::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt + 1); - if ((err & ios::failbit) == 0) checked_set(s, duration_cast(seconds{tm.tm_sec}), not_a_second, is); - is.setstate(err); - } -#endif - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } else - read(is, *fmt); - break; - case 'T': - if (command) { - if (modified == CharT{}) { - using dfs = detail::decimal_format_seconds; - CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width; - int tH = not_a_hour; - int tM = not_a_minute; - long double S; - read(is, ru{tH, 1, 2}, CharT{':'}, ru{tM, 1, 2}, CharT{':'}, rld{S, 1, w}); - checked_set(H, tH, not_a_hour, is); - checked_set(M, tM, not_a_minute, is); - checked_set(s, round(duration{S}), not_a_second, is); - } else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } else - read(is, *fmt); - break; - case 'Y': - if (command) { -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#else - if (modified != CharT{'O'}) -#endif - { - int tY = not_a_year; - read(is, rs{tY, 1, width == -1 ? 4u : static_cast(width)}); - checked_set(Y, tY, not_a_year, is); - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'E'}) { - ios::iostate err = ios::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt + 1); - if ((err & ios::failbit) == 0) checked_set(Y, tm.tm_year + 1900, not_a_year, is); - is.setstate(err); - } -#endif - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } else - read(is, *fmt); - break; - case 'y': - if (command) { -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#endif - { - int ty = not_a_2digit_year; - read(is, ru{ty, 1, width == -1 ? 2u : static_cast(width)}); - checked_set(y, ty, not_a_2digit_year, is); - } -#if !ONLY_C_LOCALE - else { - ios::iostate err = ios::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt + 1); - if ((err & ios::failbit) == 0) checked_set(Y, tm.tm_year + 1900, not_a_year, is); - is.setstate(err); - } -#endif - command = nullptr; - width = -1; - modified = CharT{}; - } else - read(is, *fmt); - break; - case 'g': - if (command) { - if (modified == CharT{}) { - int tg = not_a_2digit_year; - read(is, ru{tg, 1, width == -1 ? 2u : static_cast(width)}); - checked_set(g, tg, not_a_2digit_year, is); - } else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } else - read(is, *fmt); - break; - case 'G': - if (command) { - if (modified == CharT{}) { - int tG = not_a_year; - read(is, rs{tG, 1, width == -1 ? 4u : static_cast(width)}); - checked_set(G, tG, not_a_year, is); - } else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } else - read(is, *fmt); - break; - case 'U': - if (command) { - if (modified == CharT{}) { - int tU = not_a_week_num; - read(is, ru{tU, 1, width == -1 ? 2u : static_cast(width)}); - checked_set(U, tU, not_a_week_num, is); - } else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } else - read(is, *fmt); - break; - case 'V': - if (command) { - if (modified == CharT{}) { - int tV = not_a_week_num; - read(is, ru{tV, 1, width == -1 ? 2u : static_cast(width)}); - checked_set(V, tV, not_a_week_num, is); - } else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } else - read(is, *fmt); - break; - case 'W': - if (command) { - if (modified == CharT{}) { - int tW = not_a_week_num; - read(is, ru{tW, 1, width == -1 ? 2u : static_cast(width)}); - checked_set(W, tW, not_a_week_num, is); - } else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } else - read(is, *fmt); - break; - case 'E': - case 'O': - if (command) { - if (modified == CharT{}) { - modified = *fmt; - } else { - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - } else - read(is, *fmt); - break; - case '%': - if (command) { - if (modified == CharT{}) - read(is, *fmt); - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } else - command = fmt; - break; - case 'z': - if (command) { - int tH, tM; - minutes toff = not_a_offset; - bool neg = false; - auto ic = is.peek(); - if (!Traits::eq_int_type(ic, Traits::eof())) { - auto c = static_cast(Traits::to_char_type(ic)); - if (c == '-') neg = true; - } - if (modified == CharT{}) { - read(is, rs{tH, 2, 2}); - if (!is.fail()) toff = hours{std::abs(tH)}; - if (is.good()) { - ic = is.peek(); - if (!Traits::eq_int_type(ic, Traits::eof())) { - auto c = static_cast(Traits::to_char_type(ic)); - if ('0' <= c && c <= '9') { - read(is, ru{tM, 2, 2}); - if (!is.fail()) toff += minutes{tM}; - } - } - } - } else { - read(is, rs{tH, 1, 2}); - if (!is.fail()) toff = hours{std::abs(tH)}; - if (is.good()) { - ic = is.peek(); - if (!Traits::eq_int_type(ic, Traits::eof())) { - auto c = static_cast(Traits::to_char_type(ic)); - if (c == ':') { - (void)is.get(); - read(is, ru{tM, 2, 2}); - if (!is.fail()) toff += minutes{tM}; - } - } - } - } - if (neg) toff = -toff; - checked_set(temp_offset, toff, not_a_offset, is); - command = nullptr; - width = -1; - modified = CharT{}; - } else - read(is, *fmt); - break; - case 'Z': - if (command) { - if (modified == CharT{}) { - std::basic_string buf; - while (is.rdstate() == std::ios::goodbit) { - auto i = is.rdbuf()->sgetc(); - if (Traits::eq_int_type(i, Traits::eof())) { - is.setstate(ios::eofbit); - break; - } - auto wc = Traits::to_char_type(i); - auto c = static_cast(wc); - // is c a valid time zone name or abbreviation character? - if (!(CharT{1} < wc && wc < CharT{127}) || !(isalnum(c) || c == '_' || c == '/' || c == '-' || c == '+')) break; - buf.push_back(c); - is.rdbuf()->sbumpc(); - } - if (buf.empty()) is.setstate(ios::failbit); - checked_set(temp_abbrev, buf, {}, is); - } else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } else - read(is, *fmt); - break; - default: - if (command) { - if (width == -1 && modified == CharT{} && '0' <= *fmt && *fmt <= '9') { - width = static_cast(*fmt) - '0'; - while ('0' <= fmt[1] && fmt[1] <= '9') width = 10 * width + static_cast(*++fmt) - '0'; - } else { - if (modified == CharT{}) - read(is, CharT{'%'}, width, *fmt); - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - } else // !command - { - if (isspace(static_cast(*fmt))) { - // space matches 0 or more white space characters - if (is.good()) ws(is); - } else - read(is, *fmt); - } - break; - } - } - // is.fail() || *fmt == CharT{} - if (is.rdstate() == ios::goodbit && command) { - if (modified == CharT{}) - read(is, CharT{'%'}, width); - else - read(is, CharT{'%'}, width, modified); - } - if (!is.fail()) { - if (y != not_a_2digit_year) { - // Convert y and an optional C to Y - if (!(0 <= y && y <= 99)) goto broken; - if (C == not_a_century) { - if (Y == not_a_year) { - if (y >= 69) - C = 19; - else - C = 20; - } else { - C = (Y >= 0 ? Y : Y - 100) / 100; - } - } - int tY; - if (C >= 0) - tY = 100 * C + y; - else - tY = 100 * (C + 1) - (y == 0 ? 100 : y); - if (Y != not_a_year && Y != tY) goto broken; - Y = tY; - } - if (g != not_a_2digit_year) { - // Convert g and an optional C to G - if (!(0 <= g && g <= 99)) goto broken; - if (C == not_a_century) { - if (G == not_a_year) { - if (g >= 69) - C = 19; - else - C = 20; - } else { - C = (G >= 0 ? G : G - 100) / 100; - } - } - int tG; - if (C >= 0) - tG = 100 * C + g; - else - tG = 100 * (C + 1) - (g == 0 ? 100 : g); - if (G != not_a_year && G != tG) goto broken; - G = tG; - } - if (Y < static_cast(year::min()) || Y > static_cast(year::max())) Y = not_a_year; - bool computed = false; - if (G != not_a_year && V != not_a_week_num && wd != not_a_weekday) { - year_month_day ymd_trial = - sys_days(year{G - 1} / December / Thursday[last]) + (Monday - Thursday) + weeks{V - 1} + (weekday{static_cast(wd)} - Monday); - if (Y == not_a_year) - Y = static_cast(ymd_trial.year()); - else if (year{Y} != ymd_trial.year()) - goto broken; - if (m == not_a_month) - m = static_cast(static_cast(ymd_trial.month())); - else if (month(static_cast(m)) != ymd_trial.month()) - goto broken; - if (d == not_a_day) - d = static_cast(static_cast(ymd_trial.day())); - else if (day(static_cast(d)) != ymd_trial.day()) - goto broken; - computed = true; - } - if (Y != not_a_year && U != not_a_week_num && wd != not_a_weekday) { - year_month_day ymd_trial = sys_days(year{Y} / January / Sunday[1]) + weeks{U - 1} + (weekday{static_cast(wd)} - Sunday); - if (Y == not_a_year) - Y = static_cast(ymd_trial.year()); - else if (year{Y} != ymd_trial.year()) - goto broken; - if (m == not_a_month) - m = static_cast(static_cast(ymd_trial.month())); - else if (month(static_cast(m)) != ymd_trial.month()) - goto broken; - if (d == not_a_day) - d = static_cast(static_cast(ymd_trial.day())); - else if (day(static_cast(d)) != ymd_trial.day()) - goto broken; - computed = true; - } - if (Y != not_a_year && W != not_a_week_num && wd != not_a_weekday) { - year_month_day ymd_trial = sys_days(year{Y} / January / Monday[1]) + weeks{W - 1} + (weekday{static_cast(wd)} - Monday); - if (Y == not_a_year) - Y = static_cast(ymd_trial.year()); - else if (year{Y} != ymd_trial.year()) - goto broken; - if (m == not_a_month) - m = static_cast(static_cast(ymd_trial.month())); - else if (month(static_cast(m)) != ymd_trial.month()) - goto broken; - if (d == not_a_day) - d = static_cast(static_cast(ymd_trial.day())); - else if (day(static_cast(d)) != ymd_trial.day()) - goto broken; - computed = true; - } - if (j != not_a_doy && Y != not_a_year) { - auto ymd_trial = year_month_day{local_days(year{Y} / 1 / 1) + days{j - 1}}; - if (m == 0) - m = static_cast(static_cast(ymd_trial.month())); - else if (month(static_cast(m)) != ymd_trial.month()) - goto broken; - if (d == 0) - d = static_cast(static_cast(ymd_trial.day())); - else if (day(static_cast(d)) != ymd_trial.day()) - goto broken; - j = not_a_doy; - } - auto ymd = year{Y} / m / d; - if (ymd.ok()) { - if (wd == not_a_weekday) - wd = static_cast((weekday(sys_days(ymd)) - Sunday).count()); - else if (wd != static_cast((weekday(sys_days(ymd)) - Sunday).count())) - goto broken; - if (!computed) { - if (G != not_a_year || V != not_a_week_num) { - sys_days sd = ymd; - auto G_trial = year_month_day{sd + days{3}}.year(); - auto start = sys_days((G_trial - years{1}) / December / Thursday[last]) + (Monday - Thursday); - if (sd < start) { - --G_trial; - if (V != not_a_week_num) start = sys_days((G_trial - years{1}) / December / Thursday[last]) + (Monday - Thursday); - } - if (G != not_a_year && G != static_cast(G_trial)) goto broken; - if (V != not_a_week_num) { - auto V_trial = duration_cast(sd - start).count() + 1; - if (V != V_trial) goto broken; - } - } - if (U != not_a_week_num) { - auto start = sys_days(Sunday[1] / January / ymd.year()); - auto U_trial = floor(sys_days(ymd) - start).count() + 1; - if (U != U_trial) goto broken; - } - if (W != not_a_week_num) { - auto start = sys_days(Monday[1] / January / ymd.year()); - auto W_trial = floor(sys_days(ymd) - start).count() + 1; - if (W != W_trial) goto broken; - } - } - } - fds.ymd = ymd; - if (I != not_a_hour_12_value) { - if (!(1 <= I && I <= 12)) goto broken; - if (p != not_a_ampm) { - // p is in [0, 1] == [AM, PM] - // Store trial H in I - if (I == 12) --p; - I += p * 12; - // Either set H from I or make sure H and I are consistent - if (H == not_a_hour) - H = I; - else if (I != H) - goto broken; - } else // p == not_a_ampm - { - // if H, make sure H and I could be consistent - if (H != not_a_hour) { - if (I == 12) { - if (H != 0 && H != 12) goto broken; - } else if (!(I == H || I == H + 12)) { - goto broken; - } - } - } - } - if (H != not_a_hour) { - fds.has_tod = true; - fds.tod = hh_mm_ss{hours{H}}; - } - if (M != not_a_minute) { - fds.has_tod = true; - fds.tod.m_ = minutes{M}; - } - if (s != not_a_second) { - fds.has_tod = true; - fds.tod.s_ = detail::decimal_format_seconds{s}; - } - if (j != not_a_doy) { - fds.has_tod = true; - fds.tod.h_ += hours{days{j}}; - } - if (wd != not_a_weekday) fds.wd = weekday{static_cast(wd)}; - if (abbrev != nullptr) *abbrev = std::move(temp_abbrev); - if (offset != nullptr && temp_offset != not_a_offset) *offset = temp_offset; - } - return is; - } -broken: - is.setstate(ios::failbit); - return is; -} - -template > -std::basic_istream& from_stream(std::basic_istream& is, const CharT* fmt, year& y, - std::basic_string* abbrev = nullptr, std::chrono::minutes* offset = nullptr) { - using CT = std::chrono::seconds; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); - if (!fds.ymd.year().ok()) is.setstate(std::ios::failbit); - if (!is.fail()) y = fds.ymd.year(); - return is; -} - -template > -std::basic_istream& from_stream(std::basic_istream& is, const CharT* fmt, month& m, - std::basic_string* abbrev = nullptr, std::chrono::minutes* offset = nullptr) { - using CT = std::chrono::seconds; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); - if (!fds.ymd.month().ok()) is.setstate(std::ios::failbit); - if (!is.fail()) m = fds.ymd.month(); - return is; -} - -template > -std::basic_istream& from_stream(std::basic_istream& is, const CharT* fmt, day& d, - std::basic_string* abbrev = nullptr, std::chrono::minutes* offset = nullptr) { - using CT = std::chrono::seconds; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); - if (!fds.ymd.day().ok()) is.setstate(std::ios::failbit); - if (!is.fail()) d = fds.ymd.day(); - return is; -} - -template > -std::basic_istream& from_stream(std::basic_istream& is, const CharT* fmt, weekday& wd, - std::basic_string* abbrev = nullptr, std::chrono::minutes* offset = nullptr) { - using CT = std::chrono::seconds; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); - if (!fds.wd.ok()) is.setstate(std::ios::failbit); - if (!is.fail()) wd = fds.wd; - return is; -} - -template > -std::basic_istream& from_stream(std::basic_istream& is, const CharT* fmt, year_month& ym, - std::basic_string* abbrev = nullptr, std::chrono::minutes* offset = nullptr) { - using CT = std::chrono::seconds; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); - if (!fds.ymd.month().ok()) is.setstate(std::ios::failbit); - if (!is.fail()) ym = fds.ymd.year() / fds.ymd.month(); - return is; -} - -template > -std::basic_istream& from_stream(std::basic_istream& is, const CharT* fmt, month_day& md, - std::basic_string* abbrev = nullptr, std::chrono::minutes* offset = nullptr) { - using CT = std::chrono::seconds; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); - if (!fds.ymd.month().ok() || !fds.ymd.day().ok()) is.setstate(std::ios::failbit); - if (!is.fail()) md = fds.ymd.month() / fds.ymd.day(); - return is; -} - -template > -std::basic_istream& from_stream(std::basic_istream& is, const CharT* fmt, year_month_day& ymd, - std::basic_string* abbrev = nullptr, std::chrono::minutes* offset = nullptr) { - using CT = std::chrono::seconds; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); - if (!fds.ymd.ok()) is.setstate(std::ios::failbit); - if (!is.fail()) ymd = fds.ymd; - return is; -} - -template > -std::basic_istream& from_stream(std::basic_istream& is, const CharT* fmt, sys_time& tp, - std::basic_string* abbrev = nullptr, std::chrono::minutes* offset = nullptr) { - using CT = typename std::common_type::type; - std::chrono::minutes offset_local{}; - auto offptr = offset ? offset : &offset_local; - fields fds{}; - fds.has_tod = true; - from_stream(is, fmt, fds, abbrev, offptr); - if (!fds.ymd.ok() || !fds.tod.in_conventional_range()) is.setstate(std::ios::failbit); - if (!is.fail()) tp = round(sys_days(fds.ymd) - *offptr + fds.tod.to_duration()); - return is; -} - -template > -std::basic_istream& from_stream(std::basic_istream& is, const CharT* fmt, local_time& tp, - std::basic_string* abbrev = nullptr, std::chrono::minutes* offset = nullptr) { - using CT = typename std::common_type::type; - fields fds{}; - fds.has_tod = true; - from_stream(is, fmt, fds, abbrev, offset); - if (!fds.ymd.ok() || !fds.tod.in_conventional_range()) is.setstate(std::ios::failbit); - if (!is.fail()) tp = round(local_seconds{local_days(fds.ymd)} + fds.tod.to_duration()); - return is; -} - -template > -std::basic_istream& from_stream(std::basic_istream& is, const CharT* fmt, std::chrono::duration& d, - std::basic_string* abbrev = nullptr, std::chrono::minutes* offset = nullptr) { - using Duration = std::chrono::duration; - using CT = typename std::common_type::type; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); - if (!fds.has_tod) is.setstate(std::ios::failbit); - if (!is.fail()) d = std::chrono::duration_cast(fds.tod.to_duration()); - return is; -} - -template , class Alloc = std::allocator> -struct parse_manip { - const std::basic_string format_; - Parsable& tp_; - std::basic_string* abbrev_; - std::chrono::minutes* offset_; - - public: - parse_manip(std::basic_string format, Parsable& tp, std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) - : format_(std::move(format)), tp_(tp), abbrev_(abbrev), offset_(offset) {} -}; - -template -std::basic_istream& operator>>(std::basic_istream& is, const parse_manip& x) { - return from_stream(is, x.format_.c_str(), x.tp_, x.abbrev_, x.offset_); -} - -template -inline auto parse(const std::basic_string& format, Parsable& tp) - -> decltype(from_stream(std::declval&>(), format.c_str(), tp), parse_manip{format, tp}) { - return {format, tp}; -} - -template -inline auto parse(const std::basic_string& format, Parsable& tp, std::basic_string& abbrev) - -> decltype(from_stream(std::declval&>(), format.c_str(), tp, &abbrev), - parse_manip{format, tp, &abbrev}) { - return {format, tp, &abbrev}; -} - -template -inline auto parse(const std::basic_string& format, Parsable& tp, std::chrono::minutes& offset) - -> decltype(from_stream(std::declval&>(), format.c_str(), tp, std::declval*>(), - &offset), - parse_manip{format, tp, nullptr, &offset}) { - return {format, tp, nullptr, &offset}; -} - -template -inline auto parse(const std::basic_string& format, Parsable& tp, std::basic_string& abbrev, - std::chrono::minutes& offset) - -> decltype(from_stream(std::declval&>(), format.c_str(), tp, &abbrev, &offset), - parse_manip{format, tp, &abbrev, &offset}) { - return {format, tp, &abbrev, &offset}; -} - -// const CharT* formats - -template -inline auto parse(const CharT* format, Parsable& tp) - -> decltype(from_stream(std::declval&>(), format, tp), parse_manip{format, tp}) { - return {format, tp}; -} - -template -inline auto parse(const CharT* format, Parsable& tp, std::basic_string& abbrev) - -> decltype(from_stream(std::declval&>(), format, tp, &abbrev), - parse_manip{format, tp, &abbrev}) { - return {format, tp, &abbrev}; -} - -template -inline auto parse(const CharT* format, Parsable& tp, std::chrono::minutes& offset) - -> decltype(from_stream(std::declval&>(), format, tp, std::declval*>(), &offset), - parse_manip{format, tp, nullptr, &offset}) { - return {format, tp, nullptr, &offset}; -} - -template -inline auto parse(const CharT* format, Parsable& tp, std::basic_string& abbrev, std::chrono::minutes& offset) - -> decltype(from_stream(std::declval&>(), format, tp, &abbrev, &offset), - parse_manip{format, tp, &abbrev, &offset}) { - return {format, tp, &abbrev, &offset}; -} - -// duration streaming - -template -inline std::basic_ostream& operator<<(std::basic_ostream& os, const std::chrono::duration& d) { - return os << detail::make_string::from(d.count()) + detail::get_units(typename Period::type{}); -} - -} // namespace date - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif - -#endif diff --git a/include/ccapi_cpp/ccapi_decimal.h b/include/ccapi_cpp/ccapi_decimal.h index 4bd5e733..a5f8fd60 100644 --- a/include/ccapi_cpp/ccapi_decimal.h +++ b/include/ccapi_cpp/ccapi_decimal.h @@ -2,6 +2,7 @@ #define INCLUDE_CCAPI_CPP_CCAPI_DECIMAL_H_ #include +#include "ccapi_cpp/ccapi_logger.h" #include "ccapi_cpp/ccapi_util_private.h" namespace ccapi { /** diff --git a/include/ccapi_cpp/ccapi_event_handler.h b/include/ccapi_cpp/ccapi_event_handler.h index 5b81f914..034c06bd 100644 --- a/include/ccapi_cpp/ccapi_event_handler.h +++ b/include/ccapi_cpp/ccapi_event_handler.h @@ -10,7 +10,7 @@ class Session; class EventHandler { public: virtual ~EventHandler() {} - virtual bool processEvent(const Event& event, Session* session) { return true; } + virtual bool processEvent(const Event& event, Session* sessionPtr) { return true; } // An implementation of processEvent should process the specified // 'event' which originates from the specified 'session' and // return true to indicate events should continue to be delivered diff --git a/include/ccapi_cpp/ccapi_logger.h b/include/ccapi_cpp/ccapi_logger.h index 676ddde2..0ef57d7b 100644 --- a/include/ccapi_cpp/ccapi_logger.h +++ b/include/ccapi_cpp/ccapi_logger.h @@ -68,12 +68,12 @@ #define CCAPI_LOGGER_FUNCTION_ENTER CCAPI_LOGGER_TRACE(std::string("enter ") + std::string(__ccapi_cpp_func__)) #define CCAPI_LOGGER_FUNCTION_EXIT CCAPI_LOGGER_TRACE(std::string("exit ") + std::string(__ccapi_cpp_func__)) #include +#include #include #include -#include "ccapi_cpp/ccapi_date.h" #include "ccapi_cpp/ccapi_macro.h" -#include "ccapi_cpp/ccapi_util.h" +#include "ccapi_cpp/ccapi_util_private.h" namespace ccapi { /** * This class is used for library logging. @@ -122,11 +122,7 @@ class Logger { const std::string& fileName, const std::string& lineNumber, const std::string& message) { std::stringstream ss; ss << threadId; - this->logMessage(severity, ss.str(), getISOTimestamp(time), fileName, lineNumber, message); - } - template - static std::string getISOTimestamp(const TimePoint& tp, const std::string& fmt = "%FT%TZ") { - return date::format(fmt.c_str(), date::floor(tp)); + this->logMessage(severity, ss.str(), UtilTime::getISOTimestamp(time), fileName, lineNumber, message); } }; } /* namespace ccapi */ diff --git a/include/ccapi_cpp/ccapi_subscription.h b/include/ccapi_cpp/ccapi_subscription.h index 5f48519f..44e53bad 100644 --- a/include/ccapi_cpp/ccapi_subscription.h +++ b/include/ccapi_cpp/ccapi_subscription.h @@ -3,6 +3,7 @@ #include #include +#include "ccapi_cpp/ccapi_logger.h" #include "ccapi_cpp/ccapi_macro.h" #include "ccapi_cpp/ccapi_util_private.h" namespace ccapi { diff --git a/include/ccapi_cpp/ccapi_util.h b/include/ccapi_cpp/ccapi_util.h index 6e7bbd75..0b0f4976 100644 --- a/include/ccapi_cpp/ccapi_util.h +++ b/include/ccapi_cpp/ccapi_util.h @@ -1,6 +1,7 @@ #ifndef INCLUDE_CCAPI_CPP_CCAPI_UTIL_H_ #define INCLUDE_CCAPI_CPP_CCAPI_UTIL_H_ #include +#include namespace ccapi { typedef std::chrono::time_point TimePoint; } /* namespace ccapi */ diff --git a/include/ccapi_cpp/ccapi_util_private.h b/include/ccapi_cpp/ccapi_util_private.h index 85491b4e..c7ac957c 100644 --- a/include/ccapi_cpp/ccapi_util_private.h +++ b/include/ccapi_cpp/ccapi_util_private.h @@ -1,5 +1,8 @@ #ifndef INCLUDE_CCAPI_CPP_CCAPI_UTIL_PRIVATE_H_ #define INCLUDE_CCAPI_CPP_CCAPI_UTIL_PRIVATE_H_ +#ifdef _WIN32 +#define timegm _mkgmtime +#endif #include #include @@ -21,8 +24,7 @@ #include #include -#include "ccapi_cpp/ccapi_date.h" -#include "ccapi_cpp/ccapi_logger.h" +#include "ccapi_cpp/ccapi_macro.h" #include "ccapi_cpp/ccapi_util.h" #include "openssl/evp.h" namespace ccapi { @@ -302,7 +304,8 @@ class UtilTime CCAPI_FINAL { output += millisecondStr; return output; } - static void timePointToParts(TimePoint tp, int& year, int& month, int& day, int& hour, int& minute, int& second, int& millisecond) { + template + static void timePointToParts(TimePoint tp, int& year, int& month, int& day, int& hour, int& minute, int& second, int& fractionalSecond) { auto epoch_sec = std::chrono::time_point_cast(tp).time_since_epoch().count(); auto day_sec = epoch_sec - (epoch_sec % 86400); auto days_since_epoch = day_sec / 86400; @@ -317,28 +320,46 @@ class UtilTime CCAPI_FINAL { day = doy - (153 * mp + 2) / 5 + 1; month = mp + (mp < 10 ? 3 : -9); year += month <= 2; - auto in_day = tp - std::chrono::seconds(day_sec); - millisecond = std::chrono::time_point_cast(in_day).time_since_epoch().count(); - hour = millisecond / (60 * 60 * 1000); - millisecond -= hour * 60 * 60 * 1000; - minute = millisecond / (60 * 1000); - millisecond -= minute * 60 * 1000; - second = millisecond / 1000; - millisecond -= second * 1000; + auto in_day = tp - std::chrono::duration_cast(std::chrono::seconds(day_sec)); + auto in_day_sec_original = std::chrono::time_point_cast(in_day).time_since_epoch().count(); + auto in_day_sec = in_day_sec_original; + hour = in_day_sec / 3600; + in_day_sec -= hour * 3600; + minute = in_day_sec / 60; + second = in_day_sec - minute * 60; + auto in_day_fractional_second = in_day - std::chrono::duration_cast(std::chrono::seconds(in_day_sec_original)); + fractionalSecond = std::chrono::time_point_cast(in_day_fractional_second).time_since_epoch().count(); } static TimePoint now() { auto now = std::chrono::system_clock::now(); return TimePoint(now); } - static TimePoint parse(const std::string& s, const std::string& fmt = "%FT%TZ") { - TimePoint tp; - std::istringstream ss{s}; - ss >> date::parse(fmt, tp); - if (ss.fail()) { - CCAPI_LOGGER_FATAL("unable to parse time string"); + static TimePoint parse(const std::string& input) { + std::tm time{}; + time.tm_year = std::strtol(&input[0], nullptr, 10) - 1900; + time.tm_mon = std::strtol(&input[5], nullptr, 10) - 1; + time.tm_mday = std::strtol(&input[8], nullptr, 10); + if (input.length() > 10) { + time.tm_hour = std::strtol(&input[11], nullptr, 10); + time.tm_min = std::strtol(&input[14], nullptr, 10); + time.tm_sec = std::strtol(&input[17], nullptr, 10); } - return tp; + time.tm_isdst = 0; + long nanoseconds = 0; + if (input.length() > 20) { + std::string trail = input.substr(20); + if (trail.back() == 'Z') { + trail.pop_back(); + } + if (!trail.empty()) { + if (trail.length() > 9) { + throw std::invalid_argument("input too long"); + } + nanoseconds = std::stoll(UtilString::rightPadTo(trail, 9, '0')); + } + } + return TimePoint(std::chrono::system_clock::from_time_t(timegm(&time))) + std::chrono::nanoseconds(nanoseconds); } static TimePoint makeTimePoint(const std::pair& timePair) { auto tp = TimePoint(std::chrono::duration(timePair.first)); @@ -385,8 +406,48 @@ class UtilTime CCAPI_FINAL { return std::make_pair(std::stoll(nanoseconds.substr(0, nanoseconds.length() - 9)), std::stoll(nanoseconds.substr(nanoseconds.length() - 9))); } template - static std::string getISOTimestamp(const TimePoint& tp, const std::string& fmt = "%FT%TZ") { - return date::format(fmt.c_str(), date::floor(tp)); + static std::string getISOTimestamp(const TimePoint& tp) { + int year, month, day, hour, minute, second, fractionalSecond; + timePointToParts(tp, year, month, day, hour, minute, second, fractionalSecond); + std::string output; + output += std::to_string(year); + output += "-"; + auto monthStr = std::to_string(month); + output += std::string(2 - monthStr.length(), '0'); + output += monthStr; + output += "-"; + auto dayStr = std::to_string(day); + output += std::string(2 - dayStr.length(), '0'); + output += dayStr; + output += "T"; + auto hourStr = std::to_string(hour); + output += std::string(2 - hourStr.length(), '0'); + output += hourStr; + output += ":"; + auto minuteStr = std::to_string(minute); + output += std::string(2 - minuteStr.length(), '0'); + output += minuteStr; + output += ":"; + auto secondStr = std::to_string(second); + output += std::string(2 - secondStr.length(), '0'); + output += secondStr; + if (!std::is_same::value) { + output += "."; + auto fractionalSecondStr = std::to_string(fractionalSecond); + int padToLength; + if (std::is_same::value) { + padToLength = 9; + } else if (std::is_same::value) { + padToLength = 6; + } else if (std::is_same::value) { + padToLength = 3; + } + output += std::string(padToLength - fractionalSecondStr.length(), '0'); + // UtilString::rtrimInPlace(fractionalSecondStr, '0'); + output += fractionalSecondStr; + } + output += "Z"; + return output; } static int getUnixTimestamp(const TimePoint& tp) { auto then = tp.time_since_epoch(); @@ -415,7 +476,7 @@ class UtilAlgorithm CCAPI_FINAL { EVP_DigestInit_ex(context, EVP_sha512(), NULL); break; default: - CCAPI_LOGGER_FATAL(CCAPI_UNSUPPORTED_VALUE); + throw std::invalid_argument("invalid shaVersion"); } EVP_DigestUpdate(context, unhashed.c_str(), unhashed.length()); unsigned char hash[EVP_MAX_MD_SIZE]; diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_huobi.h b/include/ccapi_cpp/service/ccapi_execution_management_service_huobi.h index 8a318ba3..7f0eadfc 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_huobi.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_huobi.h @@ -235,7 +235,8 @@ class ExecutionManagementServiceHuobi : public ExecutionManagementServiceHuobiBa std::vector createSendStringListFromSubscription(const WsConnection& wsConnection, const Subscription& subscription, const TimePoint& now, const std::map& credential) override { auto apiKey = mapGetWithDefault(credential, this->apiKeyName); - std::string timestamp = UtilTime::getISOTimestamp(now, "%FT%T"); + std::string timestamp = UtilTime::getISOTimestamp(now); + timestamp.pop_back(); std::string signature; std::string queryString; std::map queryParamMap; diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_huobi_base.h b/include/ccapi_cpp/service/ccapi_execution_management_service_huobi_base.h index b0bd0a4f..28c8242a 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_huobi_base.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_huobi_base.h @@ -51,7 +51,8 @@ class ExecutionManagementServiceHuobiBase : public ExecutionManagementService { queryParamMap.insert(std::make_pair("AccessKeyId", apiKey)); queryParamMap.insert(std::make_pair("SignatureMethod", "HmacSHA256")); queryParamMap.insert(std::make_pair("SignatureVersion", "2")); - std::string timestamp = UtilTime::getISOTimestamp(now, "%FT%T"); + std::string timestamp = UtilTime::getISOTimestamp(now); + timestamp.pop_back(); queryParamMap.insert(std::make_pair("Timestamp", Url::urlEncode(timestamp))); std::string signature; this->createSignature(signature, queryString, methodString, this->hostRest, path, queryParamMap, credential); @@ -111,7 +112,8 @@ class ExecutionManagementServiceHuobiBase : public ExecutionManagementService { queryParamMap.insert(std::make_pair("AccessKeyId", apiKey)); queryParamMap.insert(std::make_pair("SignatureMethod", "HmacSHA256")); queryParamMap.insert(std::make_pair("SignatureVersion", "2")); - std::string timestamp = UtilTime::getISOTimestamp(now, "%FT%T"); + std::string timestamp = UtilTime::getISOTimestamp(now); + timestamp.pop_back(); queryParamMap.insert(std::make_pair("Timestamp", Url::urlEncode(timestamp))); this->convertReqDetail(req, request, now, symbolId, credential, queryParamMap); } diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_huobi_derivatives_base.h b/include/ccapi_cpp/service/ccapi_execution_management_service_huobi_derivatives_base.h index 742dcb7d..2cb61573 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_huobi_derivatives_base.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_huobi_derivatives_base.h @@ -217,7 +217,8 @@ class ExecutionManagementServiceHuobiDerivativesBase : public ExecutionManagemen std::vector createSendStringListFromSubscription(const WsConnection& wsConnection, const Subscription& subscription, const TimePoint& now, const std::map& credential) override { auto apiKey = mapGetWithDefault(credential, this->apiKeyName); - std::string timestamp = UtilTime::getISOTimestamp(now, "%FT%T"); + std::string timestamp = UtilTime::getISOTimestamp(now); + timestamp.pop_back(); std::string signature; std::string queryString; std::map queryParamMap; diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_okx.h b/include/ccapi_cpp/service/ccapi_execution_management_service_okx.h index 5eaef313..b80ae60a 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_okx.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_okx.h @@ -122,8 +122,8 @@ class ExecutionManagementServiceOkx : public ExecutionManagementService { req.set(beast::http::field::content_type, "application/json"); auto apiKey = mapGetWithDefault(credential, this->apiKeyName); req.set("OK-ACCESS-KEY", apiKey); - std::string timeStr = UtilTime::getISOTimestamp(now); - req.set("OK-ACCESS-TIMESTAMP", timeStr.substr(0, timeStr.length() - 7) + "Z"); + std::string timeStr = UtilTime::getISOTimestamp(now); + req.set("OK-ACCESS-TIMESTAMP", timeStr); auto apiPassphrase = mapGetWithDefault(credential, this->apiPassphraseName); req.set("OK-ACCESS-PASSPHRASE", apiPassphrase); auto apiXSimulatedTrading = mapGetWithDefault(credential, this->apiXSimulatedTradingName); diff --git a/performance/CMakeLists.txt b/performance/CMakeLists.txt index 848d4601..eaadb8f1 100644 --- a/performance/CMakeLists.txt +++ b/performance/CMakeLists.txt @@ -39,5 +39,5 @@ if (WIN32) set(ADDITIONAL_LINK_LIBRARIES ws2_32) endif() link_libraries(OpenSSL::Crypto OpenSSL::SSL ${ADDITIONAL_LINK_LIBRARIES}) -add_compile_options(-Wno-deprecated) +add_compile_options(-Wno-deprecated -Wno-nonnull -Wno-deprecated-declarations) add_subdirectory(src/rest_vs_fix) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e7cd7ea1..1c1e9b98 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -31,7 +31,7 @@ if (WIN32) endif() link_libraries(OpenSSL::Crypto OpenSSL::SSL ${ADDITIONAL_LINK_LIBRARIES}) set(SOURCE_LOGGER ${CCAPI_PROJECT_DIR}/test/ccapi_logger.cpp) -add_compile_options(-Wno-deprecated) +add_compile_options(-Wno-deprecated -Wno-nonnull -Wno-deprecated-declarations) if(BUILD_TEST_BUILD) add_subdirectory(test_build) endif() diff --git a/test/test_unit/src/app/historical_market_data_event_processor_test.cpp b/test/test_unit/src/app/historical_market_data_event_processor_test.cpp index 7d2f2087..3d6708c7 100644 --- a/test/test_unit/src/app/historical_market_data_event_processor_test.cpp +++ b/test/test_unit/src/app/historical_market_data_event_processor_test.cpp @@ -15,9 +15,9 @@ class HistoricalMarketDataEventProcessorTest : public ::testing::Test { this->historicalMarketDataEventProcessor->baseAsset = UtilSystem::getEnvAsString("BASE_ASSET", splitted.at(1)); this->historicalMarketDataEventProcessor->quoteAsset = UtilSystem::getEnvAsString("QUOTE_ASSET", splitted.at(2)); this->historicalMarketDataEventProcessor->historicalMarketDataStartDateTp = - UtilTime::parse(UtilSystem::getEnvAsString("HISTORICAL_MARKET_DATA_START_DATE", splitted.at(3)), "%F"); + UtilTime::parse(UtilSystem::getEnvAsString("HISTORICAL_MARKET_DATA_START_DATE", splitted.at(3))); this->historicalMarketDataEventProcessor->historicalMarketDataEndDateTp = - UtilTime::parse(UtilSystem::getEnvAsString("HISTORICAL_MARKET_DATA_END_DATE", splitted.at(4)), "%F"); + UtilTime::parse(UtilSystem::getEnvAsString("HISTORICAL_MARKET_DATA_END_DATE", splitted.at(4))); this->historicalMarketDataEventProcessor->historicalMarketDataDirectory = UtilSystem::getEnvAsString("HISTORICAL_MARKET_DATA_DIRECTORY", splitted.at(5)); this->historicalMarketDataEventProcessor->clockStepSeconds = UtilSystem::getEnvAsInt("CLOCK_STEP_MILLISECONDS", 1000) / 1000; } @@ -78,7 +78,7 @@ TEST_F(HistoricalMarketDataEventProcessorTest, processEvent) { std::vector previousSplittedMarketDepth; while (currentDateTp < this->historicalMarketDataEventProcessor->historicalMarketDataEndDateTp) { int currentSeconds; - auto currentDateISO = UtilTime::getISOTimestamp(currentDateTp, "%F"); + auto currentDateISO = UtilTime::getISOTimestamp(currentDateTp).substr(0, 10); std::string fileNameWithDirBase = this->historicalMarketDataEventProcessor->historicalMarketDataDirectory + "/" + this->historicalMarketDataEventProcessor->exchange + "__" + this->historicalMarketDataEventProcessor->baseAsset + "-" + this->historicalMarketDataEventProcessor->quoteAsset + "__" + currentDateISO + "__"; diff --git a/test/test_unit/src/common/util/ccapi_util_test.cpp b/test/test_unit/src/common/util/ccapi_util_test.cpp index d412e6bd..b4315d5e 100644 --- a/test/test_unit/src/common/util/ccapi_util_test.cpp +++ b/test/test_unit/src/common/util/ccapi_util_test.cpp @@ -1,3 +1,6 @@ +#include +#include + #include "ccapi_cpp/ccapi_util_private.h" #include "gtest/gtest.h" namespace ccapi { @@ -145,4 +148,48 @@ TEST(UtilTimeTest, divideMilliSecondsStr_5) { std::string str("1634929946010.123"); EXPECT_EQ(UtilTime::divideMilli(str), (std::make_pair(1634929946010, 123000))); } +TEST(UtilTimeTest, getISOTimestamp_1) { + std::string str("2019-11-21T01:38:23Z"); + EXPECT_EQ(UtilTime::getISOTimestamp(UtilTime::parse(str)), str); +} +TEST(UtilTimeTest, getISOTimestamp_2) { + std::string str("2019-11-21T01:38:23"); + EXPECT_EQ(UtilTime::getISOTimestamp(UtilTime::parse(str)), str + "Z"); +} +TEST(UtilTimeTest, getISOTimestamp_3) { + std::string str("2019-11-21T01:38:23.123Z"); + EXPECT_EQ(UtilTime::getISOTimestamp(UtilTime::parse(str)), str); +} +TEST(UtilTimeTest, getISOTimestamp_4) { + std::string str("2019-11-21T01:38:23.123"); + EXPECT_EQ(UtilTime::getISOTimestamp(UtilTime::parse(str)), str + "Z"); +} +TEST(UtilTimeTest, getISOTimestamp_5) { + std::string str("2019-11-21T01:38:23.123456Z"); + EXPECT_EQ(UtilTime::getISOTimestamp(UtilTime::parse(str)), str); +} +TEST(UtilTimeTest, getISOTimestamp_6) { + std::string str("2019-11-21T01:38:23.123456"); + EXPECT_EQ(UtilTime::getISOTimestamp(UtilTime::parse(str)), str + "Z"); +} +TEST(UtilTimeTest, getISOTimestamp_7) { + std::string str("2019-11-21T01:38:23.123456789Z"); + EXPECT_EQ(UtilTime::getISOTimestamp(UtilTime::parse(str)), str); +} +TEST(UtilTimeTest, getISOTimestamp_8) { + std::string str("2019-11-21T01:38:23.123456789"); + EXPECT_EQ(UtilTime::getISOTimestamp(UtilTime::parse(str)), str + "Z"); +} +TEST(UtilTimeTest, getISOTimestamp_9) { + std::string str("2019-11-21T01:38:23.123456789"); + EXPECT_EQ(UtilTime::getISOTimestamp(UtilTime::parse(str)), "2019-11-21T01:38:23Z"); +} +TEST(UtilTimeTest, getISOTimestamp_10) { + std::string str("2019-11-21"); + EXPECT_EQ(UtilTime::getISOTimestamp(UtilTime::parse(str)), "2019-11-21T00:00:00Z"); +} +TEST(UtilTimeTest, getISOTimestamp_11) { + std::string str("2019-11-21T01:38:23Z"); + EXPECT_EQ(UtilTime::getISOTimestamp(UtilTime::parse(str)), "2019-11-21T01:38:23.000Z"); +} } /* namespace ccapi */