#ifndef DATE_H #define DATE_H // 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 // // 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 # define HAS_UNCAUGHT_EXCEPTIONS 1 # else # define HAS_UNCAUGHT_EXCEPTIONS 0 # endif #endif // HAS_UNCAUGHT_EXCEPTIONS #ifndef HAS_VOID_T # if __cplusplus >= 201703 # 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 //-----------+ // Interface | //-----------+ // durations using days = std::chrono::duration , std::chrono::hours::period>::type>; using weeks = std::chrono::duration , days::period>::type>; using years = std::chrono::duration , days::period>::type>; using months = std::chrono::duration >::type>; // 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; } // inline 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 < digits < 64, std::int64_t, #ifdef __SIZEOF_INT128__ __int128 #else std::int64_t #endif >::type >::type; }; template CONSTCD11 inline typename std::enable_if < !std::chrono::treat_as_floating_point::value, T >::type trunc(T t) NOEXCEPT { return t; } template CONSTCD14 inline typename std::enable_if < std::chrono::treat_as_floating_point::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 < Yp, Xp % Yp >::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 = INTMAX_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 < mul < n1, d2, !value >::value, mul < n2, d1, !value >::value > type; }; } // detail // trunc towards zero template CONSTCD11 inline typename std::enable_if < detail::no_overflow::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 < !detail::no_overflow::value, To >::type trunc(const std::chrono::duration &d) { using std::chrono::duration_cast; using std::chrono::duration; 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 < detail::no_overflow::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 < !detail::no_overflow::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::floor; using std::chrono::ceil; using std::chrono::round; using std::chrono::abs; #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 << 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 < std::uint64_t n, std::uint64_t d = 10, unsigned w = 0, bool should_continue = !(n < 2) && d != 0 && (w < 19) > struct width { static CONSTDATA unsigned value = 1 + width < n, d % n * 10, w + 1 >::value; }; template struct width { static CONSTDATA unsigned value = 0; }; template struct static_pow10 { private: static CONSTDATA std::uint64_t h = static_pow10 < exp / 2 >::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::treat_as_floating_point::value ? d - 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 os.width(width); os << sub_s_.count(); } return os; } }; template inline CONSTCD11 typename std::enable_if < std::numeric_limits::is_signed, std::chrono::duration >::type abs(std::chrono::duration d) { return d >= d.zero() ? +d : -d; } template inline CONSTCD11 typename std::enable_if < !std::numeric_limits::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 (h_ + m_ + s_.to_duration()) * (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 -= 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 += hours{12}; } else if (h == hours{12}) h = hours{0}; return h; } template using time_of_day = hh_mm_ss; template < class Rep, class Period, class = typename std::enable_if < !std::chrono::treat_as_floating_point::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 < !std::chrono::treat_as_floating_point::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 < typename std::conditional < sizeof(CharT2) <= sizeof(CharT1), CharT1, CharT2 >::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 < class U = CharT, class = typename std::enable_if<(1 < sizeof(U))>::type> CONSTCD14 string_literal(const char(&a)[N]) NOEXCEPT : p_ {} { for (std::size_t i = 0; i < N; ++i) { p_[i] = a[i]; } } template < class CharT2, class = typename std::enable_if < !std::is_same::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 < typename std::conditional < sizeof(CharT2) <= sizeof(CharT1), CharT1, CharT2 >::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 < typename std::conditional < sizeof(CharT2) <= sizeof(CharT1), CharT1, CharT2 >::type, N1 + N2 - 1 > operator+(const string_literal &x, const string_literal &y) NOEXCEPT { using CT = typename std::conditional < sizeof(CharT2) <= sizeof(CharT1), CharT1, CharT2 >::type; string_literal < CT, N1 + N2 - 1 > 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 < class CharT, class = std::enable_if_t < std::is_same {} || std::is_same {} || std::is_same {} || std::is_same {} >> 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 < char, to_string_len(N) + 1 > > msl() NOEXCEPT { return msl(char(N % 10 + '0')); } template CONSTCD14 inline std::enable_if_t < 10 <= N, string_literal < char, to_string_len(N) + 1 > > msl() NOEXCEPT { return msl < N / 10 > () + msl(char(N % 10 + '0')); } template CONSTCD14 inline std::enable_if_t < std::ratio::type::den != 1, string_literal < CharT, to_string_len(std::ratio::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 < std::ratio::type::den == 1, string_literal < CharT, to_string_len(std::ratio::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 < std::ratio::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 < std::ratio::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 < std::is_same::value, string_literal >::type msl(std::micro) NOEXCEPT { return string_literal{'\xC2', '\xB5'}; } template CONSTCD11 inline typename std::enable_if < !std::is_same::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::weekday_names; using detail::month_names; using detail::ampm_names; #endif using detail::save_ostream; using detail::get_units; using detail::extract_weekday; using detail::extract_month; using std::ios; using std::chrono::duration_cast; using std::chrono::seconds; using std::chrono::minutes; using std::chrono::hours; 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.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'} ? 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 (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 << make12(tod.hours()).count() << CharT{':'}; os.width(2); os << tod.minutes().count() << CharT{':'}; os.width(2); os << tod.seconds().count() << CharT{' '}; if (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 { 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 + 2] = {}; 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::numeric_limits; using std::ios; using std::chrono::duration; using std::chrono::duration_cast; using std::chrono::seconds; using std::chrono::minutes; using std::chrono::hours; 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::read; using detail::rs; using detail::ru; using detail::rld; using detail::checked_set; 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 // DATE_H