7906 lines
202 KiB
C++
7906 lines
202 KiB
C++
#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 <cassert>
|
|
#include <algorithm>
|
|
#include <cctype>
|
|
#include <chrono>
|
|
#include <climits>
|
|
#if !(__cplusplus >= 201402)
|
|
# include <cmath>
|
|
#endif
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
#include <ctime>
|
|
#include <ios>
|
|
#include <istream>
|
|
#include <iterator>
|
|
#include <limits>
|
|
#include <locale>
|
|
#include <memory>
|
|
#include <ostream>
|
|
#include <ratio>
|
|
#include <sstream>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#if HAS_STRING_VIEW
|
|
# include <string_view>
|
|
#endif
|
|
#include <utility>
|
|
#include <type_traits>
|
|
|
|
#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
|
|
<int, std::ratio_multiply<std::ratio<24>, std::chrono::hours::period>::type>;
|
|
|
|
using weeks = std::chrono::duration
|
|
<int, std::ratio_multiply<std::ratio<7>, days::period>::type>;
|
|
|
|
using years = std::chrono::duration
|
|
<int, std::ratio_multiply<std::ratio<146097, 400>, days::period>::type>;
|
|
|
|
using months = std::chrono::duration
|
|
<int, std::ratio_divide<years::period, std::ratio<12>>::type>;
|
|
|
|
// time_point
|
|
|
|
template <class Duration>
|
|
using sys_time = std::chrono::time_point<std::chrono::system_clock, Duration>;
|
|
|
|
using sys_days = sys_time<days>;
|
|
using sys_seconds = sys_time<std::chrono::seconds>;
|
|
|
|
struct local_t {};
|
|
|
|
template <class Duration>
|
|
using local_time = std::chrono::time_point<local_t, Duration>;
|
|
|
|
using local_seconds = local_time<std::chrono::seconds>;
|
|
using local_days = local_time<days>;
|
|
|
|
// 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<class CharT, class Traits>
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &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<class CharT, class Traits>
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &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<class CharT, class Traits>
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &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<class CharT, class Traits>
|
|
friend std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &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<class CharT, class Traits>
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &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<class CharT, class Traits>
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &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<class CharT, class Traits>
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &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<class = detail::unspecified_month_disambiguator>
|
|
CONSTCD14 year_month & operator+=(const months &dm) NOEXCEPT;
|
|
template<class = detail::unspecified_month_disambiguator>
|
|
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<class = detail::unspecified_month_disambiguator>
|
|
CONSTCD14 year_month operator+(const year_month &ym, const months &dm) NOEXCEPT;
|
|
template<class = detail::unspecified_month_disambiguator>
|
|
CONSTCD14 year_month operator+(const months &dm, const year_month &ym) NOEXCEPT;
|
|
template<class = detail::unspecified_month_disambiguator>
|
|
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<class CharT, class Traits>
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &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<class CharT, class Traits>
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &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<class CharT, class Traits>
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &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<class CharT, class Traits>
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &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<class CharT, class Traits>
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &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<class = detail::unspecified_month_disambiguator>
|
|
CONSTCD14 year_month_day & operator+=(const months &m) NOEXCEPT;
|
|
template<class = detail::unspecified_month_disambiguator>
|
|
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<class = detail::unspecified_month_disambiguator>
|
|
CONSTCD14 year_month_day operator+(const year_month_day &ymd,
|
|
const months &dm) NOEXCEPT;
|
|
template<class = detail::unspecified_month_disambiguator>
|
|
CONSTCD14 year_month_day operator+(const months &dm,
|
|
const year_month_day &ymd) NOEXCEPT;
|
|
template<class = detail::unspecified_month_disambiguator>
|
|
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<class CharT, class Traits>
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &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<class = detail::unspecified_month_disambiguator>
|
|
CONSTCD14 year_month_day_last & operator+=(const months &m) NOEXCEPT;
|
|
template<class = detail::unspecified_month_disambiguator>
|
|
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<class = detail::unspecified_month_disambiguator>
|
|
CONSTCD14
|
|
year_month_day_last
|
|
operator+(const year_month_day_last &ymdl, const months &dm) NOEXCEPT;
|
|
|
|
template<class = detail::unspecified_month_disambiguator>
|
|
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<class = detail::unspecified_month_disambiguator>
|
|
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<class CharT, class Traits>
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &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<class = detail::unspecified_month_disambiguator>
|
|
CONSTCD14 year_month_weekday & operator+=(const months &m) NOEXCEPT;
|
|
template<class = detail::unspecified_month_disambiguator>
|
|
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<class = detail::unspecified_month_disambiguator>
|
|
CONSTCD14
|
|
year_month_weekday
|
|
operator+(const year_month_weekday &ymwd, const months &dm) NOEXCEPT;
|
|
|
|
template<class = detail::unspecified_month_disambiguator>
|
|
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<class = detail::unspecified_month_disambiguator>
|
|
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<class CharT, class Traits>
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &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<class = detail::unspecified_month_disambiguator>
|
|
CONSTCD14 year_month_weekday_last & operator+=(const months &m) NOEXCEPT;
|
|
template<class = detail::unspecified_month_disambiguator>
|
|
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<class = detail::unspecified_month_disambiguator>
|
|
CONSTCD14
|
|
year_month_weekday_last
|
|
operator+(const year_month_weekday_last &ymwdl, const months &dm) NOEXCEPT;
|
|
|
|
template<class = detail::unspecified_month_disambiguator>
|
|
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<class = detail::unspecified_month_disambiguator>
|
|
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<class CharT, class Traits>
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &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 <class T, class = std::void_t<>>
|
|
struct is_clock
|
|
: std::false_type {
|
|
};
|
|
|
|
template <class T>
|
|
struct is_clock<T, std::void_t<decltype(T::now()), typename T::rep, typename T::period,
|
|
typename T::duration, typename T::time_point,
|
|
decltype(T::is_steady)>>
|
|
: std::true_type {
|
|
};
|
|
|
|
#endif // HAS_VOID_T
|
|
|
|
//----------------+
|
|
// Implementation |
|
|
//----------------+
|
|
|
|
// utilities
|
|
namespace detail {
|
|
|
|
template<class CharT, class Traits = std::char_traits<CharT>>
|
|
class save_istream {
|
|
protected:
|
|
std::basic_ios<CharT, Traits> &is_;
|
|
CharT fill_;
|
|
std::ios::fmtflags flags_;
|
|
std::streamsize width_;
|
|
std::basic_ostream<CharT, Traits> *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<CharT, Traits> &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 CharT, class Traits = std::char_traits<CharT>>
|
|
class save_ostream
|
|
: private save_istream<CharT, Traits> {
|
|
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<CharT, Traits> &os)
|
|
: save_istream<CharT, Traits>(os)
|
|
{
|
|
}
|
|
};
|
|
|
|
template <class T>
|
|
struct choose_trunc_type {
|
|
static const int digits = std::numeric_limits<T>::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 <class T>
|
|
CONSTCD11
|
|
inline
|
|
typename std::enable_if
|
|
<
|
|
!std::chrono::treat_as_floating_point<T>::value,
|
|
T
|
|
>::type
|
|
trunc(T t) NOEXCEPT {
|
|
return t;
|
|
}
|
|
|
|
template <class T>
|
|
CONSTCD14
|
|
inline
|
|
typename std::enable_if
|
|
<
|
|
std::chrono::treat_as_floating_point<T>::value,
|
|
T
|
|
>::type
|
|
trunc(T t) NOEXCEPT {
|
|
using std::numeric_limits;
|
|
using I = typename choose_trunc_type<T>::type;
|
|
CONSTDATA auto digits = numeric_limits<T>::digits;
|
|
static_assert(digits < numeric_limits<I>::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<T>(static_cast<I>(t));
|
|
if (t == 0 && negative) {
|
|
t = -t;
|
|
}
|
|
}
|
|
return t;
|
|
}
|
|
|
|
template <std::intmax_t Xp, std::intmax_t Yp>
|
|
struct static_gcd {
|
|
static const std::intmax_t value = static_gcd < Yp, Xp % Yp >::value;
|
|
};
|
|
|
|
template <std::intmax_t Xp>
|
|
struct static_gcd<Xp, 0> {
|
|
static const std::intmax_t value = Xp;
|
|
};
|
|
|
|
template <>
|
|
struct static_gcd<0, 0> {
|
|
static const std::intmax_t value = 1;
|
|
};
|
|
|
|
template <class R1, class R2>
|
|
struct no_overflow {
|
|
private:
|
|
static const std::intmax_t gcd_n1_n2 = static_gcd<R1::num, R2::num>::value;
|
|
static const std::intmax_t gcd_d1_d2 = static_gcd<R1::den, R2::den>::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 <std::intmax_t Xp, std::intmax_t Yp, bool overflow>
|
|
struct mul { // overflow == false
|
|
static const std::intmax_t value = Xp * Yp;
|
|
};
|
|
|
|
template <std::intmax_t Xp, std::intmax_t Yp>
|
|
struct mul<Xp, Yp, true> {
|
|
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 <class To, class Rep, class Period>
|
|
CONSTCD11
|
|
inline
|
|
typename std::enable_if
|
|
<
|
|
detail::no_overflow<Period, typename To::period>::value,
|
|
To
|
|
>::type
|
|
trunc(const std::chrono::duration<Rep, Period> &d)
|
|
{
|
|
return To{detail::trunc(std::chrono::duration_cast<To>(d).count())};
|
|
}
|
|
|
|
template <class To, class Rep, class Period>
|
|
CONSTCD11
|
|
inline
|
|
typename std::enable_if
|
|
<
|
|
!detail::no_overflow<Period, typename To::period>::value,
|
|
To
|
|
>::type
|
|
trunc(const std::chrono::duration<Rep, Period> &d)
|
|
{
|
|
using std::chrono::duration_cast;
|
|
using std::chrono::duration;
|
|
using rep = typename std::common_type<Rep, typename To::rep>::type;
|
|
return To{detail::trunc(duration_cast<To>(duration_cast<duration<rep>>(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 <class To, class Rep, class Period>
|
|
CONSTCD14
|
|
inline
|
|
typename std::enable_if
|
|
<
|
|
detail::no_overflow<Period, typename To::period>::value,
|
|
To
|
|
>::type
|
|
floor(const std::chrono::duration<Rep, Period> &d)
|
|
{
|
|
auto t = trunc<To>(d);
|
|
if (t > d)
|
|
return t - To{1};
|
|
return t;
|
|
}
|
|
|
|
template <class To, class Rep, class Period>
|
|
CONSTCD14
|
|
inline
|
|
typename std::enable_if
|
|
<
|
|
!detail::no_overflow<Period, typename To::period>::value,
|
|
To
|
|
>::type
|
|
floor(const std::chrono::duration<Rep, Period> &d)
|
|
{
|
|
using rep = typename std::common_type<Rep, typename To::rep>::type;
|
|
return floor<To>(floor<std::chrono::duration<rep>>(d));
|
|
}
|
|
|
|
// round to nearest, to even on tie
|
|
template <class To, class Rep, class Period>
|
|
CONSTCD14
|
|
inline
|
|
To
|
|
round(const std::chrono::duration<Rep, Period> &d)
|
|
{
|
|
auto t0 = floor<To>(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<To>(t0 / 2) * 2 == To{0})
|
|
return t0;
|
|
return t1;
|
|
}
|
|
if (diff0 < diff1) {
|
|
return t0;
|
|
}
|
|
return t1;
|
|
}
|
|
|
|
// round up
|
|
template <class To, class Rep, class Period>
|
|
CONSTCD14
|
|
inline
|
|
To
|
|
ceil(const std::chrono::duration<Rep, Period> &d)
|
|
{
|
|
auto t = trunc<To>(d);
|
|
if (t < d)
|
|
return t + To{1};
|
|
return t;
|
|
}
|
|
|
|
template <class Rep, class Period,
|
|
class = typename std::enable_if
|
|
<
|
|
std::numeric_limits<Rep>::is_signed
|
|
>::type>
|
|
CONSTCD11
|
|
std::chrono::duration<Rep, Period>
|
|
abs(std::chrono::duration<Rep, Period> d)
|
|
{
|
|
return d >= d.zero() ? d : -d;
|
|
}
|
|
|
|
// round down
|
|
template <class To, class Clock, class FromDuration>
|
|
CONSTCD11
|
|
inline
|
|
std::chrono::time_point<Clock, To>
|
|
floor(const std::chrono::time_point<Clock, FromDuration> &tp)
|
|
{
|
|
using std::chrono::time_point;
|
|
return time_point<Clock, To> {date::floor<To>(tp.time_since_epoch())};
|
|
}
|
|
|
|
// round to nearest, to even on tie
|
|
template <class To, class Clock, class FromDuration>
|
|
CONSTCD11
|
|
inline
|
|
std::chrono::time_point<Clock, To>
|
|
round(const std::chrono::time_point<Clock, FromDuration> &tp)
|
|
{
|
|
using std::chrono::time_point;
|
|
return time_point<Clock, To> {round<To>(tp.time_since_epoch())};
|
|
}
|
|
|
|
// round up
|
|
template <class To, class Clock, class FromDuration>
|
|
CONSTCD11
|
|
inline
|
|
std::chrono::time_point<Clock, To>
|
|
ceil(const std::chrono::time_point<Clock, FromDuration> &tp)
|
|
{
|
|
using std::chrono::time_point;
|
|
return time_point<Clock, To> {ceil<To>(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 <class To, class Clock, class FromDuration>
|
|
CONSTCD11
|
|
inline
|
|
std::chrono::time_point<Clock, To>
|
|
trunc(const std::chrono::time_point<Clock, FromDuration> &tp)
|
|
{
|
|
using std::chrono::time_point;
|
|
return time_point<Clock, To> {trunc<To>(tp.time_since_epoch())};
|
|
}
|
|
|
|
// day
|
|
|
|
CONSTCD11 inline day::day(unsigned d) NOEXCEPT :
|
|
d_(static_cast<unsigned char>(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<unsigned>(x) == static_cast<unsigned>(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<unsigned>(x) < static_cast<unsigned>(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<days::rep>(static_cast<unsigned>(x)
|
|
- static_cast<unsigned>(y))};
|
|
}
|
|
|
|
CONSTCD11
|
|
inline
|
|
day
|
|
operator+(const day &x, const days &y) NOEXCEPT {
|
|
return day{static_cast<unsigned>(x) + static_cast<unsigned>(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<class CharT, class Traits>
|
|
inline
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &os, const day &d)
|
|
{
|
|
detail::save_ostream<CharT, Traits> _(os);
|
|
os.fill('0');
|
|
os.flags(std::ios::dec | std::ios::right);
|
|
os.width(2);
|
|
os << static_cast<unsigned>(d);
|
|
if (!d.ok()) {
|
|
os << " is not a valid day";
|
|
}
|
|
return os;
|
|
}
|
|
|
|
// month
|
|
|
|
CONSTCD11 inline month::month(unsigned m) NOEXCEPT :
|
|
m_(static_cast<decltype(m_)>(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<unsigned>(x) == static_cast<unsigned>(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<unsigned>(x) < static_cast<unsigned>(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<unsigned>(x) - static_cast<unsigned>(y);
|
|
return months(d <= 11 ? d : d + 12);
|
|
}
|
|
|
|
CONSTCD14
|
|
inline
|
|
month
|
|
operator+(const month &x, const months &y) NOEXCEPT {
|
|
auto const mu = static_cast<long long>(static_cast<unsigned>(x)) + (y.count() - 1);
|
|
auto const yr = (mu >= 0 ? mu : mu - 11) / 12;
|
|
return month{static_cast<unsigned>(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<class CharT, class Traits>
|
|
inline
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &os, const month &m)
|
|
{
|
|
if (m.ok()) {
|
|
CharT fmt[] = {'%', 'b', 0};
|
|
os << format(os.getloc(), fmt, m);
|
|
}
|
|
else {
|
|
os << static_cast<unsigned>(m) << " is not a valid month";
|
|
}
|
|
return os;
|
|
}
|
|
|
|
// year
|
|
|
|
CONSTCD11 inline year::year(int y) NOEXCEPT :
|
|
y_(static_cast<decltype(y_)>(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<short>::min();
|
|
}
|
|
|
|
CONSTCD11
|
|
inline
|
|
bool
|
|
operator==(const year &x, const year &y) NOEXCEPT {
|
|
return static_cast<int>(x) == static_cast<int>(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<int>(x) < static_cast<int>(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<int>(x) - static_cast<int>(y)};
|
|
}
|
|
|
|
CONSTCD11
|
|
inline
|
|
year
|
|
operator+(const year &x, const years &y) NOEXCEPT {
|
|
return year{static_cast<int>(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<int>(x) - y.count()};
|
|
}
|
|
|
|
template<class CharT, class Traits>
|
|
inline
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &os, const year &y)
|
|
{
|
|
detail::save_ostream<CharT, Traits> _(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<int>(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<unsigned>(z);
|
|
return static_cast<unsigned char>(z >= -4 ? (u + 4) % 7 : u % 7);
|
|
}
|
|
|
|
CONSTCD11
|
|
inline
|
|
weekday::weekday(unsigned wd) NOEXCEPT
|
|
:
|
|
wd_(static_cast<decltype(wd_)>(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<long long>(static_cast<unsigned>(x.wd_)) + y.count();
|
|
auto const wk = (wdu >= 0 ? wdu : wdu - 6) / 7;
|
|
return weekday{static_cast<unsigned>(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<class CharT, class Traits>
|
|
inline
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &os, const weekday &wd)
|
|
{
|
|
if (wd.ok()) {
|
|
CharT fmt[] = {'%', 'a', 0};
|
|
os << format(fmt, wd);
|
|
}
|
|
else {
|
|
os << static_cast<unsigned>(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<unsigned>(d)};
|
|
}
|
|
|
|
CONSTCD11
|
|
inline
|
|
date::year
|
|
operator "" _y(unsigned long long y) NOEXCEPT {
|
|
return date::year(static_cast<int>(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<unsigned>(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<decltype(wd_)>(static_cast<unsigned>(wd.wd_)))
|
|
, index_(static_cast<decltype(index_)>(index))
|
|
{}
|
|
|
|
#ifdef __GNUC__
|
|
# pragma GCC diagnostic pop
|
|
#endif // __GNUC__
|
|
|
|
template<class CharT, class Traits>
|
|
inline
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &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<class CharT, class Traits>
|
|
inline
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &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<class>
|
|
CONSTCD14
|
|
inline
|
|
year_month &
|
|
year_month::operator+=(const months &dm) NOEXCEPT {
|
|
*this = *this + dm;
|
|
return *this;
|
|
}
|
|
|
|
template<class>
|
|
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<class>
|
|
CONSTCD14
|
|
inline
|
|
year_month
|
|
operator+(const year_month &ym, const months &dm) NOEXCEPT {
|
|
auto dmi = static_cast<int>(static_cast<unsigned>(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<unsigned>(dmi));
|
|
}
|
|
|
|
template<class>
|
|
CONSTCD14
|
|
inline
|
|
year_month
|
|
operator+(const months &dm, const year_month &ym) NOEXCEPT {
|
|
return ym + dm;
|
|
}
|
|
|
|
template<class>
|
|
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<unsigned>(x.month()) - static_cast<unsigned>(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<class CharT, class Traits>
|
|
inline
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &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<unsigned>(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<class CharT, class Traits>
|
|
inline
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &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<class CharT, class Traits>
|
|
inline
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &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<class CharT, class Traits>
|
|
inline
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &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<class CharT, class Traits>
|
|
inline
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &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<class>
|
|
CONSTCD14
|
|
inline
|
|
year_month_day_last &
|
|
year_month_day_last::operator+=(const months &m) NOEXCEPT {
|
|
*this = *this + m;
|
|
return *this;
|
|
}
|
|
|
|
template<class>
|
|
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<unsigned>(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<class CharT, class Traits>
|
|
inline
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &os,
|
|
const year_month_day_last &ymdl)
|
|
{
|
|
return os << ymdl.year() << '/' << ymdl.month_day_last();
|
|
}
|
|
|
|
template<class>
|
|
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<class>
|
|
CONSTCD14
|
|
inline
|
|
year_month_day_last
|
|
operator+(const months &dm, const year_month_day_last &ymdl) NOEXCEPT {
|
|
return ymdl + dm;
|
|
}
|
|
|
|
template<class>
|
|
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<class>
|
|
CONSTCD14
|
|
inline
|
|
year_month_day &
|
|
year_month_day::operator+=(const months &m) NOEXCEPT {
|
|
*this = *this + m;
|
|
return *this;
|
|
}
|
|
|
|
template<class>
|
|
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<unsigned>::digits >= 18,
|
|
"This algorithm has not been ported to a 16 bit unsigned integer");
|
|
static_assert(std::numeric_limits<int>::digits >= 20,
|
|
"This algorithm has not been ported to a 16 bit signed integer");
|
|
auto const y = static_cast<int>(y_) - (m_ <= February);
|
|
auto const m = static_cast<unsigned>(m_);
|
|
auto const d = static_cast<unsigned>(d_);
|
|
auto const era = (y >= 0 ? y : y - 399) / 400;
|
|
auto const yoe = static_cast<unsigned>(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<int>(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<class CharT, class Traits>
|
|
inline
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &os, const year_month_day &ymd)
|
|
{
|
|
detail::save_ostream<CharT, Traits> _(os);
|
|
os.fill('0');
|
|
os.flags(std::ios::dec | std::ios::right);
|
|
os << ymd.year() << '-';
|
|
os.width(2);
|
|
os << static_cast<unsigned>(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<unsigned>::digits >= 18,
|
|
"This algorithm has not been ported to a 16 bit unsigned integer");
|
|
static_assert(std::numeric_limits<int>::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<unsigned>(z - era * 146097); // [0, 146096]
|
|
auto const yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365; // [0, 399]
|
|
auto const y = static_cast<days::rep>(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<class>
|
|
CONSTCD14
|
|
inline
|
|
year_month_day
|
|
operator+(const year_month_day &ymd, const months &dm) NOEXCEPT {
|
|
return (ymd.year() / ymd.month() + dm) / ymd.day();
|
|
}
|
|
|
|
template<class>
|
|
CONSTCD14
|
|
inline
|
|
year_month_day
|
|
operator+(const months &dm, const year_month_day &ymd) NOEXCEPT {
|
|
return ymd + dm;
|
|
}
|
|
|
|
template<class>
|
|
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<class>
|
|
CONSTCD14
|
|
inline
|
|
year_month_weekday &
|
|
year_month_weekday::operator+=(const months &m) NOEXCEPT {
|
|
*this = *this + m;
|
|
return *this;
|
|
}
|
|
|
|
template<class>
|
|
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<sys_days>(y_ / m_ / 1)) +
|
|
days((wdi_.index() - 1) * 7 + 1);
|
|
return static_cast<unsigned>(d2.count()) <= static_cast<unsigned>((
|
|
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<unsigned>(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<class CharT, class Traits>
|
|
inline
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &os,
|
|
const year_month_weekday &ymwdi)
|
|
{
|
|
return os << ymwdi.year() << '/' << ymwdi.month()
|
|
<< '/' << ymwdi.weekday_indexed();
|
|
}
|
|
|
|
template<class>
|
|
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<class>
|
|
CONSTCD14
|
|
inline
|
|
year_month_weekday
|
|
operator+(const months &dm, const year_month_weekday &ymwd) NOEXCEPT {
|
|
return ymwd + dm;
|
|
}
|
|
|
|
template<class>
|
|
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<class>
|
|
CONSTCD14
|
|
inline
|
|
year_month_weekday_last &
|
|
year_month_weekday_last::operator+=(const months &m) NOEXCEPT {
|
|
*this = *this + m;
|
|
return *this;
|
|
}
|
|
|
|
template<class>
|
|
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<class CharT, class Traits>
|
|
inline
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &os,
|
|
const year_month_weekday_last &ymwdl)
|
|
{
|
|
return os << ymwdl.year() << '/' << ymwdl.month() << '/' <<
|
|
ymwdl.weekday_last();
|
|
}
|
|
|
|
template<class>
|
|
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<class>
|
|
CONSTCD14
|
|
inline
|
|
year_month_weekday_last
|
|
operator+(const months &dm, const year_month_weekday_last &ymwdl) NOEXCEPT {
|
|
return ymwdl + dm;
|
|
}
|
|
|
|
template<class>
|
|
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<unsigned>(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<unsigned>(d));
|
|
}
|
|
|
|
CONSTCD11
|
|
inline
|
|
month_day
|
|
operator/(int m, const day &d) NOEXCEPT {
|
|
return month(static_cast<unsigned>(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<unsigned>(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<unsigned>(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<unsigned>(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<unsigned>(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 <class Duration>
|
|
struct fields;
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
std::basic_ostream<CharT, Traits> &
|
|
to_stream(std::basic_ostream<CharT, Traits> &os, const CharT *fmt,
|
|
const fields<Duration> &fds, const std::string *abbrev = nullptr,
|
|
const std::chrono::seconds *offset_sec = nullptr);
|
|
|
|
template <class CharT, class Traits, class Duration, class Alloc>
|
|
std::basic_istream<CharT, Traits> &
|
|
from_stream(std::basic_istream<CharT, Traits> &is, const CharT *fmt,
|
|
fields<Duration> &fds, std::basic_string<CharT, Traits, Alloc> *abbrev =
|
|
nullptr,
|
|
std::chrono::minutes *offset = nullptr);
|
|
|
|
// hh_mm_ss
|
|
|
|
namespace detail {
|
|
|
|
struct undocumented {
|
|
explicit undocumented() = default;
|
|
};
|
|
|
|
// width<n>::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 <std::uint64_t n, std::uint64_t d, unsigned w>
|
|
struct width<n, d, w, false> {
|
|
static CONSTDATA unsigned value = 0;
|
|
};
|
|
|
|
template <unsigned exp>
|
|
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 Duration>
|
|
class decimal_format_seconds {
|
|
using CT = typename std::common_type<Duration, std::chrono::seconds>::type;
|
|
using rep = typename CT::rep;
|
|
public:
|
|
static unsigned constexpr width = detail::width<CT::period::den>::value < 19 ?
|
|
detail::width<CT::period::den>::value : 6u;
|
|
using precision = std::chrono::duration<rep,
|
|
std::ratio<1, static_pow10<width>::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<std::chrono::seconds>(d))
|
|
, sub_s_(std::chrono::treat_as_floating_point<rep>::value ? d - s_ :
|
|
std::chrono::duration_cast<precision>(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 <class CharT, class Traits>
|
|
friend
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &os,
|
|
const decimal_format_seconds &x)
|
|
{
|
|
return x.print(os, std::chrono::treat_as_floating_point<rep> {});
|
|
}
|
|
|
|
template <class CharT, class Traits>
|
|
std::basic_ostream<CharT, Traits> &
|
|
print(std::basic_ostream<CharT, Traits> &os, std::true_type) const
|
|
{
|
|
date::detail::save_ostream<CharT, Traits> _(os);
|
|
std::chrono::duration<rep> d = s_ + sub_s_;
|
|
if (d < std::chrono::seconds{10})
|
|
os << '0';
|
|
os << std::fixed << d.count();
|
|
return os;
|
|
}
|
|
|
|
template <class CharT, class Traits>
|
|
std::basic_ostream<CharT, Traits> &
|
|
print(std::basic_ostream<CharT, Traits> &os, std::false_type) const
|
|
{
|
|
date::detail::save_ostream<CharT, Traits> _(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<std::numpunct<CharT>>(os.getloc()).decimal_point();
|
|
#else
|
|
os << '.';
|
|
#endif
|
|
os.width(width);
|
|
os << sub_s_.count();
|
|
}
|
|
return os;
|
|
}
|
|
};
|
|
|
|
template <class Rep, class Period>
|
|
inline
|
|
CONSTCD11
|
|
typename std::enable_if
|
|
<
|
|
std::numeric_limits<Rep>::is_signed,
|
|
std::chrono::duration<Rep, Period>
|
|
>::type
|
|
abs(std::chrono::duration<Rep, Period> d)
|
|
{
|
|
return d >= d.zero() ? +d : -d;
|
|
}
|
|
|
|
template <class Rep, class Period>
|
|
inline
|
|
CONSTCD11
|
|
typename std::enable_if
|
|
<
|
|
!std::numeric_limits<Rep>::is_signed,
|
|
std::chrono::duration<Rep, Period>
|
|
>::type
|
|
abs(std::chrono::duration<Rep, Period> d)
|
|
{
|
|
return d;
|
|
}
|
|
|
|
} // namespace detail
|
|
|
|
template <class Duration>
|
|
class hh_mm_ss {
|
|
using dfs = detail::decimal_format_seconds<typename std::common_type<Duration,
|
|
std::chrono::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<std::chrono::hours>(detail::abs(d)))
|
|
, m_(std::chrono::duration_cast<std::chrono::minutes>(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 <class charT, class traits>
|
|
friend
|
|
std::basic_ostream<charT, traits> &
|
|
operator<<(std::basic_ostream<charT, traits> &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 <class CharT, class Traits, class Duration2>
|
|
friend
|
|
std::basic_ostream<CharT, Traits> &
|
|
date::to_stream(std::basic_ostream<CharT, Traits> &os, const CharT *fmt,
|
|
const fields<Duration2> &fds, const std::string *abbrev,
|
|
const std::chrono::seconds *offset_sec);
|
|
|
|
template <class CharT, class Traits, class Duration2, class Alloc>
|
|
friend
|
|
std::basic_istream<CharT, Traits> &
|
|
date::from_stream(std::basic_istream<CharT, Traits> &is, const CharT *fmt,
|
|
fields<Duration2> &fds,
|
|
std::basic_string<CharT, Traits, Alloc> *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 <class Duration>
|
|
using time_of_day = hh_mm_ss<Duration>;
|
|
|
|
template < class Rep, class Period,
|
|
class = typename std::enable_if
|
|
< !std::chrono::treat_as_floating_point<Rep>::value >::type >
|
|
CONSTCD11
|
|
inline
|
|
hh_mm_ss<std::chrono::duration<Rep, Period>>
|
|
make_time(const std::chrono::duration<Rep, Period> &d)
|
|
{
|
|
return hh_mm_ss<std::chrono::duration<Rep, Period>>(d);
|
|
}
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
inline
|
|
typename std::enable_if
|
|
<
|
|
!std::chrono::treat_as_floating_point<typename Duration::rep>::value &&
|
|
std::ratio_less<typename Duration::period, days::period>::value
|
|
, std::basic_ostream<CharT, Traits> &
|
|
>::type
|
|
operator<<(std::basic_ostream<CharT, Traits> &os, const sys_time<Duration> &tp)
|
|
{
|
|
auto const dp = date::floor<days>(tp);
|
|
return os << year_month_day(dp) << ' ' << make_time(tp - dp);
|
|
}
|
|
|
|
template <class CharT, class Traits>
|
|
inline
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &os, const sys_days &dp)
|
|
{
|
|
return os << year_month_day(dp);
|
|
}
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
inline
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &os,
|
|
const local_time<Duration> &ut)
|
|
{
|
|
return (os << sys_time<Duration> {ut.time_since_epoch()});
|
|
}
|
|
|
|
namespace detail {
|
|
|
|
template <class CharT, std::size_t N>
|
|
class string_literal;
|
|
|
|
template <class CharT1, class CharT2, std::size_t N1, std::size_t N2>
|
|
inline
|
|
CONSTCD14
|
|
string_literal < typename std::conditional < sizeof(CharT2) <= sizeof(CharT1),
|
|
CharT1, CharT2 >::type,
|
|
N1 + N2 - 1 >
|
|
operator+(const string_literal<CharT1, N1> &x,
|
|
const string_literal<CharT2, N2> &y) NOEXCEPT;
|
|
|
|
template <class CharT, std::size_t N>
|
|
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 <std::size_t N1 = 2,
|
|
class = typename std::enable_if<N1 == N>::type>
|
|
CONSTCD11 string_literal(CharT c) NOEXCEPT
|
|
:
|
|
p_{c} {
|
|
}
|
|
|
|
template <std::size_t N1 = 3,
|
|
class = typename std::enable_if<N1 == N>::type>
|
|
CONSTCD11 string_literal(CharT c1, CharT c2) NOEXCEPT
|
|
:
|
|
p_{c1, c2} {
|
|
}
|
|
|
|
template <std::size_t N1 = 4,
|
|
class = typename std::enable_if<N1 == N>::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<CharT2, CharT>::value >::type >
|
|
CONSTCD14 string_literal(string_literal<CharT2, N> 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 <class Traits>
|
|
friend
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &os, const string_literal &s)
|
|
{
|
|
return os << s.p_;
|
|
}
|
|
|
|
template <class CharT1, class CharT2, std::size_t N1, std::size_t N2>
|
|
friend
|
|
CONSTCD14
|
|
string_literal < typename std::conditional < sizeof(CharT2) <= sizeof(CharT1),
|
|
CharT1, CharT2 >::type,
|
|
N1 + N2 - 1 >
|
|
operator+(const string_literal<CharT1, N1> &x,
|
|
const string_literal<CharT2, N2> &y) NOEXCEPT;
|
|
};
|
|
|
|
template <class CharT>
|
|
CONSTCD11
|
|
inline
|
|
string_literal<CharT, 3>
|
|
operator+(const string_literal<CharT, 2> &x,
|
|
const string_literal<CharT, 2> &y) NOEXCEPT {
|
|
return string_literal<CharT, 3>(x[0], y[0]);
|
|
}
|
|
|
|
template <class CharT>
|
|
CONSTCD11
|
|
inline
|
|
string_literal<CharT, 4>
|
|
operator+(const string_literal<CharT, 3> &x,
|
|
const string_literal<CharT, 2> &y) NOEXCEPT {
|
|
return string_literal<CharT, 4>(x[0], x[1], y[0]);
|
|
}
|
|
|
|
template <class CharT1, class CharT2, std::size_t N1, std::size_t N2>
|
|
CONSTCD14
|
|
inline
|
|
string_literal < typename std::conditional < sizeof(CharT2) <= sizeof(CharT1),
|
|
CharT1, CharT2 >::type,
|
|
N1 + N2 - 1 >
|
|
operator+(const string_literal<CharT1, N1> &x,
|
|
const string_literal<CharT2, N2> &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 <class CharT, class Traits, class Alloc, std::size_t N>
|
|
inline
|
|
std::basic_string<CharT, Traits, Alloc>
|
|
operator+(std::basic_string<CharT, Traits, Alloc> x,
|
|
const string_literal<CharT, N> &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<CharT, char> {} ||
|
|
std::is_same<CharT, wchar_t> {} ||
|
|
std::is_same<CharT, char16_t> {} ||
|
|
std::is_same<CharT, char32_t> {} >>
|
|
CONSTCD14
|
|
inline
|
|
string_literal<CharT, 2>
|
|
msl(CharT c) NOEXCEPT {
|
|
return string_literal<CharT, 2>{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 <std::intmax_t N>
|
|
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 <std::intmax_t N>
|
|
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 <class CharT, std::intmax_t N, std::intmax_t D>
|
|
CONSTCD14
|
|
inline
|
|
std::enable_if_t
|
|
<
|
|
std::ratio<N, D>::type::den != 1,
|
|
string_literal < CharT, to_string_len(std::ratio<N, D>::type::num) +
|
|
to_string_len(std::ratio<N, D>::type::den) + 4 >
|
|
>
|
|
msl(std::ratio<N, D>) NOEXCEPT {
|
|
using R = typename std::ratio<N, D>::type;
|
|
return msl(CharT{'['}) + msl<R::num>() + msl(CharT{'/'}) +
|
|
msl<R::den>() + msl(CharT{']'});
|
|
}
|
|
|
|
template <class CharT, std::intmax_t N, std::intmax_t D>
|
|
CONSTCD14
|
|
inline
|
|
std::enable_if_t
|
|
<
|
|
std::ratio<N, D>::type::den == 1,
|
|
string_literal < CharT, to_string_len(std::ratio<N, D>::type::num) + 3 >
|
|
>
|
|
msl(std::ratio<N, D>) NOEXCEPT {
|
|
using R = typename std::ratio<N, D>::type;
|
|
return msl(CharT{'['}) + msl<R::num>() + 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 <class CharT>
|
|
inline
|
|
std::basic_string<CharT>
|
|
to_string(std::uint64_t x)
|
|
{
|
|
auto y = std::to_string(x);
|
|
return std::basic_string<CharT>(y.begin(), y.end());
|
|
}
|
|
|
|
template <class CharT, std::intmax_t N, std::intmax_t D>
|
|
inline
|
|
typename std::enable_if
|
|
<
|
|
std::ratio<N, D>::type::den != 1,
|
|
std::basic_string<CharT>
|
|
>::type
|
|
msl(std::ratio<N, D>)
|
|
{
|
|
using R = typename std::ratio<N, D>::type;
|
|
return std::basic_string<CharT>(1, '[') + to_string<CharT>(R::num) + CharT{'/'} +
|
|
to_string<CharT>(R::den) + CharT{']'};
|
|
}
|
|
|
|
template <class CharT, std::intmax_t N, std::intmax_t D>
|
|
inline
|
|
typename std::enable_if
|
|
<
|
|
std::ratio<N, D>::type::den == 1,
|
|
std::basic_string<CharT>
|
|
>::type
|
|
msl(std::ratio<N, D>)
|
|
{
|
|
using R = typename std::ratio<N, D>::type;
|
|
return std::basic_string<CharT>(1, '[') + to_string<CharT>(R::num) + CharT{']'};
|
|
}
|
|
|
|
#endif // __cplusplus < 201402 || (defined(__EDG_VERSION__) && __EDG_VERSION__ <= 411)
|
|
|
|
template <class CharT>
|
|
CONSTCD11
|
|
inline
|
|
string_literal<CharT, 2>
|
|
msl(std::atto) NOEXCEPT {
|
|
return string_literal<CharT, 2>{'a'};
|
|
}
|
|
|
|
template <class CharT>
|
|
CONSTCD11
|
|
inline
|
|
string_literal<CharT, 2>
|
|
msl(std::femto) NOEXCEPT {
|
|
return string_literal<CharT, 2>{'f'};
|
|
}
|
|
|
|
template <class CharT>
|
|
CONSTCD11
|
|
inline
|
|
string_literal<CharT, 2>
|
|
msl(std::pico) NOEXCEPT {
|
|
return string_literal<CharT, 2>{'p'};
|
|
}
|
|
|
|
template <class CharT>
|
|
CONSTCD11
|
|
inline
|
|
string_literal<CharT, 2>
|
|
msl(std::nano) NOEXCEPT {
|
|
return string_literal<CharT, 2>{'n'};
|
|
}
|
|
|
|
template <class CharT>
|
|
CONSTCD11
|
|
inline
|
|
typename std::enable_if
|
|
<
|
|
std::is_same<CharT, char>::value,
|
|
string_literal<char, 3>
|
|
>::type
|
|
msl(std::micro) NOEXCEPT {
|
|
return string_literal<char, 3>{'\xC2', '\xB5'};
|
|
}
|
|
|
|
template <class CharT>
|
|
CONSTCD11
|
|
inline
|
|
typename std::enable_if
|
|
<
|
|
!std::is_same<CharT, char>::value,
|
|
string_literal<CharT, 2>
|
|
>::type
|
|
msl(std::micro) NOEXCEPT {
|
|
return string_literal<CharT, 2>{CharT{static_cast<unsigned char>('\xB5')}};
|
|
}
|
|
|
|
template <class CharT>
|
|
CONSTCD11
|
|
inline
|
|
string_literal<CharT, 2>
|
|
msl(std::milli) NOEXCEPT {
|
|
return string_literal<CharT, 2>{'m'};
|
|
}
|
|
|
|
template <class CharT>
|
|
CONSTCD11
|
|
inline
|
|
string_literal<CharT, 2>
|
|
msl(std::centi) NOEXCEPT {
|
|
return string_literal<CharT, 2>{'c'};
|
|
}
|
|
|
|
template <class CharT>
|
|
CONSTCD11
|
|
inline
|
|
string_literal<CharT, 3>
|
|
msl(std::deca) NOEXCEPT {
|
|
return string_literal<CharT, 3>{'d', 'a'};
|
|
}
|
|
|
|
template <class CharT>
|
|
CONSTCD11
|
|
inline
|
|
string_literal<CharT, 2>
|
|
msl(std::deci) NOEXCEPT {
|
|
return string_literal<CharT, 2>{'d'};
|
|
}
|
|
|
|
template <class CharT>
|
|
CONSTCD11
|
|
inline
|
|
string_literal<CharT, 2>
|
|
msl(std::hecto) NOEXCEPT {
|
|
return string_literal<CharT, 2>{'h'};
|
|
}
|
|
|
|
template <class CharT>
|
|
CONSTCD11
|
|
inline
|
|
string_literal<CharT, 2>
|
|
msl(std::kilo) NOEXCEPT {
|
|
return string_literal<CharT, 2>{'k'};
|
|
}
|
|
|
|
template <class CharT>
|
|
CONSTCD11
|
|
inline
|
|
string_literal<CharT, 2>
|
|
msl(std::mega) NOEXCEPT {
|
|
return string_literal<CharT, 2>{'M'};
|
|
}
|
|
|
|
template <class CharT>
|
|
CONSTCD11
|
|
inline
|
|
string_literal<CharT, 2>
|
|
msl(std::giga) NOEXCEPT {
|
|
return string_literal<CharT, 2>{'G'};
|
|
}
|
|
|
|
template <class CharT>
|
|
CONSTCD11
|
|
inline
|
|
string_literal<CharT, 2>
|
|
msl(std::tera) NOEXCEPT {
|
|
return string_literal<CharT, 2>{'T'};
|
|
}
|
|
|
|
template <class CharT>
|
|
CONSTCD11
|
|
inline
|
|
string_literal<CharT, 2>
|
|
msl(std::peta) NOEXCEPT {
|
|
return string_literal<CharT, 2>{'P'};
|
|
}
|
|
|
|
template <class CharT>
|
|
CONSTCD11
|
|
inline
|
|
string_literal<CharT, 2>
|
|
msl(std::exa) NOEXCEPT {
|
|
return string_literal<CharT, 2>{'E'};
|
|
}
|
|
|
|
template <class CharT, class Period>
|
|
CONSTCD11
|
|
inline
|
|
auto
|
|
get_units(Period p)
|
|
-> decltype(msl<CharT>(p) + string_literal<CharT, 2> {'s'})
|
|
{
|
|
return msl<CharT>(p) + string_literal<CharT, 2> {'s'};
|
|
}
|
|
|
|
template <class CharT>
|
|
CONSTCD11
|
|
inline
|
|
string_literal<CharT, 2>
|
|
get_units(std::ratio<1>)
|
|
{
|
|
return string_literal<CharT, 2> {'s'};
|
|
}
|
|
|
|
template <class CharT>
|
|
CONSTCD11
|
|
inline
|
|
string_literal<CharT, 2>
|
|
get_units(std::ratio<3600>)
|
|
{
|
|
return string_literal<CharT, 2> {'h'};
|
|
}
|
|
|
|
template <class CharT>
|
|
CONSTCD11
|
|
inline
|
|
string_literal<CharT, 4>
|
|
get_units(std::ratio<60>)
|
|
{
|
|
return string_literal<CharT, 4> {'m', 'i', 'n'};
|
|
}
|
|
|
|
template <class CharT>
|
|
CONSTCD11
|
|
inline
|
|
string_literal<CharT, 2>
|
|
get_units(std::ratio<86400>)
|
|
{
|
|
return string_literal<CharT, 2> {'d'};
|
|
}
|
|
|
|
template <class CharT, class Traits = std::char_traits<CharT>>
|
|
struct make_string;
|
|
|
|
template <>
|
|
struct make_string<char> {
|
|
template <class Rep>
|
|
static
|
|
std::string
|
|
from(Rep n)
|
|
{
|
|
return std::to_string(n);
|
|
}
|
|
};
|
|
|
|
template <class Traits>
|
|
struct make_string<char, Traits> {
|
|
template <class Rep>
|
|
static
|
|
std::basic_string<char, Traits>
|
|
from(Rep n)
|
|
{
|
|
auto s = std::to_string(n);
|
|
return std::basic_string<char, Traits>(s.begin(), s.end());
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct make_string<wchar_t> {
|
|
template <class Rep>
|
|
static
|
|
std::wstring
|
|
from(Rep n)
|
|
{
|
|
return std::to_wstring(n);
|
|
}
|
|
};
|
|
|
|
template <class Traits>
|
|
struct make_string<wchar_t, Traits> {
|
|
template <class Rep>
|
|
static
|
|
std::basic_string<wchar_t, Traits>
|
|
from(Rep n)
|
|
{
|
|
auto s = std::to_wstring(n);
|
|
return std::basic_string<wchar_t, Traits>(s.begin(), s.end());
|
|
}
|
|
};
|
|
|
|
} // namespace detail
|
|
|
|
// to_stream
|
|
|
|
CONSTDATA year nanyear{-32768};
|
|
|
|
template <class Duration>
|
|
struct fields {
|
|
year_month_day ymd{nanyear / 0 / 0};
|
|
weekday wd{8u};
|
|
hh_mm_ss<Duration> tod{};
|
|
bool has_tod = false;
|
|
|
|
fields() = default;
|
|
|
|
fields(year_month_day ymd_) : ymd(ymd_) {}
|
|
fields(weekday wd_) : wd(wd_) {}
|
|
fields(hh_mm_ss<Duration> 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<Duration> tod_) : ymd(ymd_), tod(tod_),
|
|
has_tod(true) {}
|
|
|
|
fields(weekday wd_, hh_mm_ss<Duration> tod_) : wd(wd_), tod(tod_),
|
|
has_tod(true) {}
|
|
|
|
fields(year_month_day ymd_, weekday wd_, hh_mm_ss<Duration> tod_)
|
|
: ymd(ymd_)
|
|
, wd(wd_)
|
|
, tod(tod_)
|
|
, has_tod(true)
|
|
{}
|
|
};
|
|
|
|
namespace detail {
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
unsigned
|
|
extract_weekday(std::basic_ostream<CharT, Traits> &os,
|
|
const fields<Duration> &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<unsigned>((wd - Sunday).count());
|
|
}
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
unsigned
|
|
extract_month(std::basic_ostream<CharT, Traits> &os,
|
|
const fields<Duration> &fds)
|
|
{
|
|
if (!fds.ymd.month().ok()) {
|
|
// fds does not contain a valid month
|
|
os.setstate(std::ios::failbit);
|
|
return 0;
|
|
}
|
|
return static_cast<unsigned>(fds.ymd.month());
|
|
}
|
|
|
|
} // namespace detail
|
|
|
|
#if ONLY_C_LOCALE
|
|
|
|
namespace detail {
|
|
|
|
inline
|
|
std::pair<const std::string *, const std::string *>
|
|
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<const std::string *, const std::string *>
|
|
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<const std::string *, const std::string *>
|
|
ampm_names()
|
|
{
|
|
static const std::string nm[] = {
|
|
"AM",
|
|
"PM"
|
|
};
|
|
return std::make_pair(nm, nm + sizeof(nm) / sizeof(nm[0]));
|
|
}
|
|
|
|
template <class CharT, class Traits, class FwdIter>
|
|
FwdIter
|
|
scan_keyword(std::basic_istream<CharT, Traits> &is, FwdIter kb, FwdIter ke)
|
|
{
|
|
size_t nkw = static_cast<size_t>(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<unsigned char, void(*)(void *)> 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<char>(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<char>(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 <class CharT, class Traits, class Duration>
|
|
std::basic_ostream<CharT, Traits> &
|
|
to_stream(std::basic_ostream<CharT, Traits> &os, const CharT *fmt,
|
|
const fields<Duration> &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<CharT, Traits> 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<std::time_put<CharT>>(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<int>(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<int>(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<int>(fds.tod.seconds().count());
|
|
tm.tm_min = static_cast<int>(fds.tod.minutes().count());
|
|
tm.tm_hour = static_cast<int>(fds.tod.hours().count());
|
|
}
|
|
tm.tm_mday = static_cast<int>(static_cast<unsigned>(ymd.day()));
|
|
tm.tm_mon = static_cast<int>(extract_month(os, fds) - 1);
|
|
tm.tm_year = static_cast<int>(ymd.year()) - 1900;
|
|
tm.tm_wday = static_cast<int>(extract_weekday(os, fds));
|
|
if (os.fail()) {
|
|
return os;
|
|
}
|
|
tm.tm_yday = static_cast<int>((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<int>(extract_weekday(os, fds));
|
|
os << weekday_names().first[static_cast<unsigned>(wd) + 7]
|
|
<< ' ';
|
|
os << month_names().first[extract_month(os, fds) - 1 + 12] << ' ';
|
|
auto d = static_cast<int>(static_cast<unsigned>(fds.ymd.day()));
|
|
if (d < 10) {
|
|
os << ' ';
|
|
}
|
|
os << d << ' '
|
|
<< make_time(duration_cast<seconds>(fds.tod.to_duration()))
|
|
<< ' ' << fds.ymd.year();
|
|
|
|
}
|
|
else { // *fmt == 'x'
|
|
auto const &ymd = fds.ymd;
|
|
save_ostream<CharT, Traits> _(os);
|
|
os.fill('0');
|
|
os.flags(std::ios::dec | std::ios::right);
|
|
os.width(2);
|
|
os << static_cast<unsigned>(ymd.month()) << CharT{'/'};
|
|
os.width(2);
|
|
os << static_cast<unsigned>(ymd.day()) << CharT{'/'};
|
|
os.width(2);
|
|
os << static_cast<int>(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<int>(fds.ymd.year());
|
|
#if !ONLY_C_LOCALE
|
|
if (modified == CharT {})
|
|
#endif
|
|
{
|
|
save_ostream<CharT, Traits> _(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<int>(static_cast<unsigned>(fds.ymd.day()));
|
|
#if !ONLY_C_LOCALE
|
|
if (modified == CharT {})
|
|
#endif
|
|
{
|
|
save_ostream<CharT, Traits> _(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<CharT, Traits> _(os);
|
|
os.fill('0');
|
|
os.flags(std::ios::dec | std::ios::right);
|
|
os.width(2);
|
|
os << static_cast<unsigned>(ymd.month()) << CharT{'/'};
|
|
os.width(2);
|
|
os << static_cast<unsigned>(ymd.day()) << CharT{'/'};
|
|
os.width(2);
|
|
os << static_cast<int>(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<CharT, Traits> _(os);
|
|
os.fill('0');
|
|
os.flags(std::ios::dec | std::ios::right);
|
|
os.width(4);
|
|
os << static_cast<int>(ymd.year()) << CharT{'-'};
|
|
os.width(2);
|
|
os << static_cast<unsigned>(ymd.month()) << CharT{'-'};
|
|
os.width(2);
|
|
os << static_cast<unsigned>(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<CharT, Traits> _(os);
|
|
os.fill('0');
|
|
os.flags(std::ios::dec | std::ios::right);
|
|
os.width(2);
|
|
os << std::abs(static_cast<int>(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<int>(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<days>(fds.tod.to_duration());
|
|
}
|
|
save_ostream<CharT, Traits> _(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<unsigned>(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<int>(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<int>(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<int>(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<CharT>(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<int>(fds.tod.hours().count());
|
|
tm.tm_min = static_cast<int>(fds.tod.minutes().count());
|
|
tm.tm_sec = static_cast<int>(fds.tod.seconds().count());
|
|
facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));
|
|
#else
|
|
hh_mm_ss<seconds> tod(duration_cast<seconds>(fds.tod.to_duration()));
|
|
save_ostream<CharT, Traits> _(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<int>(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<int>(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<weeks>(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<int>(ymd.year()) - 1900;
|
|
tm.tm_wday = static_cast<int>(extract_weekday(os, fds));
|
|
if (os.fail()) {
|
|
return os;
|
|
}
|
|
tm.tm_yday = static_cast<int>((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<weeks>(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<int>(ymd.year()) - 1900;
|
|
tm.tm_wday = static_cast<int>(extract_weekday(os, fds));
|
|
if (os.fail()) {
|
|
return os;
|
|
}
|
|
tm.tm_yday = static_cast<int>((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<int>(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<weeks>(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<int>(ymd.year()) - 1900;
|
|
tm.tm_wday = static_cast<int>(extract_weekday(os, fds));
|
|
if (os.fail()) {
|
|
return os;
|
|
}
|
|
tm.tm_yday = static_cast<int>((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<int>(fds.tod.seconds().count());
|
|
tm.tm_min = static_cast<int>(fds.tod.minutes().count());
|
|
tm.tm_hour = static_cast<int>(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<int>(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<int>(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<minutes>(*offset_sec);
|
|
auto neg = m < minutes{0};
|
|
m = date::abs(m);
|
|
auto h = duration_cast<hours>(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 <class CharT, class Traits>
|
|
inline
|
|
std::basic_ostream<CharT, Traits> &
|
|
to_stream(std::basic_ostream<CharT, Traits> &os, const CharT *fmt,
|
|
const year &y)
|
|
{
|
|
using CT = std::chrono::seconds;
|
|
fields<CT> fds{y / 0 / 0};
|
|
return to_stream(os, fmt, fds);
|
|
}
|
|
|
|
template <class CharT, class Traits>
|
|
inline
|
|
std::basic_ostream<CharT, Traits> &
|
|
to_stream(std::basic_ostream<CharT, Traits> &os, const CharT *fmt,
|
|
const month &m)
|
|
{
|
|
using CT = std::chrono::seconds;
|
|
fields<CT> fds{m / 0 / nanyear};
|
|
return to_stream(os, fmt, fds);
|
|
}
|
|
|
|
template <class CharT, class Traits>
|
|
inline
|
|
std::basic_ostream<CharT, Traits> &
|
|
to_stream(std::basic_ostream<CharT, Traits> &os, const CharT *fmt, const day &d)
|
|
{
|
|
using CT = std::chrono::seconds;
|
|
fields<CT> fds{d / 0 / nanyear};
|
|
return to_stream(os, fmt, fds);
|
|
}
|
|
|
|
template <class CharT, class Traits>
|
|
inline
|
|
std::basic_ostream<CharT, Traits> &
|
|
to_stream(std::basic_ostream<CharT, Traits> &os, const CharT *fmt,
|
|
const weekday &wd)
|
|
{
|
|
using CT = std::chrono::seconds;
|
|
fields<CT> fds{wd};
|
|
return to_stream(os, fmt, fds);
|
|
}
|
|
|
|
template <class CharT, class Traits>
|
|
inline
|
|
std::basic_ostream<CharT, Traits> &
|
|
to_stream(std::basic_ostream<CharT, Traits> &os, const CharT *fmt,
|
|
const year_month &ym)
|
|
{
|
|
using CT = std::chrono::seconds;
|
|
fields<CT> fds{ym / 0};
|
|
return to_stream(os, fmt, fds);
|
|
}
|
|
|
|
template <class CharT, class Traits>
|
|
inline
|
|
std::basic_ostream<CharT, Traits> &
|
|
to_stream(std::basic_ostream<CharT, Traits> &os, const CharT *fmt,
|
|
const month_day &md)
|
|
{
|
|
using CT = std::chrono::seconds;
|
|
fields<CT> fds{md / nanyear};
|
|
return to_stream(os, fmt, fds);
|
|
}
|
|
|
|
template <class CharT, class Traits>
|
|
inline
|
|
std::basic_ostream<CharT, Traits> &
|
|
to_stream(std::basic_ostream<CharT, Traits> &os, const CharT *fmt,
|
|
const year_month_day &ymd)
|
|
{
|
|
using CT = std::chrono::seconds;
|
|
fields<CT> fds{ymd};
|
|
return to_stream(os, fmt, fds);
|
|
}
|
|
|
|
template <class CharT, class Traits, class Rep, class Period>
|
|
inline
|
|
std::basic_ostream<CharT, Traits> &
|
|
to_stream(std::basic_ostream<CharT, Traits> &os, const CharT *fmt,
|
|
const std::chrono::duration<Rep, Period> &d)
|
|
{
|
|
using Duration = std::chrono::duration<Rep, Period>;
|
|
using CT = typename std::common_type<Duration, std::chrono::seconds>::type;
|
|
fields<CT> fds{hh_mm_ss<CT>{d}};
|
|
return to_stream(os, fmt, fds);
|
|
}
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
std::basic_ostream<CharT, Traits> &
|
|
to_stream(std::basic_ostream<CharT, Traits> &os, const CharT *fmt,
|
|
const local_time<Duration> &tp, const std::string *abbrev = nullptr,
|
|
const std::chrono::seconds *offset_sec = nullptr)
|
|
{
|
|
using CT = typename std::common_type<Duration, std::chrono::seconds>::type;
|
|
auto ld = floor<days>(tp);
|
|
fields<CT> fds{year_month_day{ld}, hh_mm_ss<CT>{tp - local_seconds{ld}}};
|
|
return to_stream(os, fmt, fds, abbrev, offset_sec);
|
|
}
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
std::basic_ostream<CharT, Traits> &
|
|
to_stream(std::basic_ostream<CharT, Traits> &os, const CharT *fmt,
|
|
const sys_time<Duration> &tp)
|
|
{
|
|
using std::chrono::seconds;
|
|
using CT = typename std::common_type<Duration, seconds>::type;
|
|
const std::string abbrev("UTC");
|
|
CONSTDATA seconds offset{0};
|
|
auto sd = floor<days>(tp);
|
|
fields<CT> fds{year_month_day{sd}, hh_mm_ss<CT>{tp - sys_seconds{sd}}};
|
|
return to_stream(os, fmt, fds, &abbrev, &offset);
|
|
}
|
|
|
|
// format
|
|
|
|
template <class CharT, class Streamable>
|
|
auto
|
|
format(const std::locale &loc, const CharT *fmt, const Streamable &tp)
|
|
-> decltype(to_stream(std::declval<std::basic_ostream<CharT>&>(), fmt, tp),
|
|
std::basic_string<CharT> {})
|
|
{
|
|
std::basic_ostringstream<CharT> os;
|
|
os.exceptions(std::ios::failbit | std::ios::badbit);
|
|
os.imbue(loc);
|
|
to_stream(os, fmt, tp);
|
|
return os.str();
|
|
}
|
|
|
|
template <class CharT, class Streamable>
|
|
auto
|
|
format(const CharT *fmt, const Streamable &tp)
|
|
-> decltype(to_stream(std::declval<std::basic_ostream<CharT>&>(), fmt, tp),
|
|
std::basic_string<CharT> {})
|
|
{
|
|
std::basic_ostringstream<CharT> os;
|
|
os.exceptions(std::ios::failbit | std::ios::badbit);
|
|
to_stream(os, fmt, tp);
|
|
return os.str();
|
|
}
|
|
|
|
template <class CharT, class Traits, class Alloc, class Streamable>
|
|
auto
|
|
format(const std::locale &loc,
|
|
const std::basic_string<CharT, Traits, Alloc> &fmt,
|
|
const Streamable &tp)
|
|
-> decltype(to_stream(std::declval<std::basic_ostream<CharT, Traits>&>(),
|
|
fmt.c_str(), tp),
|
|
std::basic_string<CharT, Traits, Alloc> {})
|
|
{
|
|
std::basic_ostringstream<CharT, Traits, Alloc> os;
|
|
os.exceptions(std::ios::failbit | std::ios::badbit);
|
|
os.imbue(loc);
|
|
to_stream(os, fmt.c_str(), tp);
|
|
return os.str();
|
|
}
|
|
|
|
template <class CharT, class Traits, class Alloc, class Streamable>
|
|
auto
|
|
format(const std::basic_string<CharT, Traits, Alloc> &fmt, const Streamable &tp)
|
|
-> decltype(to_stream(std::declval<std::basic_ostream<CharT, Traits>&>(),
|
|
fmt.c_str(), tp),
|
|
std::basic_string<CharT, Traits, Alloc> {})
|
|
{
|
|
std::basic_ostringstream<CharT, Traits, Alloc> os;
|
|
os.exceptions(std::ios::failbit | std::ios::badbit);
|
|
to_stream(os, fmt.c_str(), tp);
|
|
return os.str();
|
|
}
|
|
|
|
// parse
|
|
|
|
namespace detail {
|
|
|
|
template <class CharT, class Traits>
|
|
bool
|
|
read_char(std::basic_istream<CharT, Traits> &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 <class CharT, class Traits>
|
|
unsigned
|
|
read_unsigned(std::basic_istream<CharT, Traits> &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<char>(Traits::to_char_type(ic));
|
|
if (!('0' <= c && c <= '9')) {
|
|
break;
|
|
}
|
|
(void)is.get();
|
|
++count;
|
|
x = 10 * x + static_cast<unsigned>(c - '0');
|
|
if (count == M) {
|
|
break;
|
|
}
|
|
}
|
|
if (count < m) {
|
|
is.setstate(std::ios::failbit);
|
|
}
|
|
return x;
|
|
}
|
|
|
|
template <class CharT, class Traits>
|
|
int
|
|
read_signed(std::basic_istream<CharT, Traits> &is, unsigned m = 1,
|
|
unsigned M = 10)
|
|
{
|
|
auto ic = is.peek();
|
|
if (!Traits::eq_int_type(ic, Traits::eof())) {
|
|
auto c = static_cast<char>(Traits::to_char_type(ic));
|
|
if (('0' <= c && c <= '9') || c == '-' || c == '+') {
|
|
if (c == '-' || c == '+') {
|
|
(void)is.get();
|
|
}
|
|
auto x = static_cast<int>(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 <class CharT, class Traits>
|
|
long double
|
|
read_long_double(std::basic_istream<CharT, Traits> &is, unsigned m = 1,
|
|
unsigned M = 10)
|
|
{
|
|
unsigned count = 0;
|
|
auto decimal_point = Traits::to_int_type(
|
|
std::use_facet<std::numpunct<CharT>>(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<char>(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 <class CharT, class Traits>
|
|
void
|
|
read(std::basic_istream<CharT, Traits> &)
|
|
{
|
|
}
|
|
|
|
template <class CharT, class Traits, class ...Args>
|
|
void
|
|
read(std::basic_istream<CharT, Traits> &is, CharT a0, Args &&...args);
|
|
|
|
template <class CharT, class Traits, class ...Args>
|
|
void
|
|
read(std::basic_istream<CharT, Traits> &is, rs a0, Args &&...args);
|
|
|
|
template <class CharT, class Traits, class ...Args>
|
|
void
|
|
read(std::basic_istream<CharT, Traits> &is, ru a0, Args &&...args);
|
|
|
|
template <class CharT, class Traits, class ...Args>
|
|
void
|
|
read(std::basic_istream<CharT, Traits> &is, int a0, Args &&...args);
|
|
|
|
template <class CharT, class Traits, class ...Args>
|
|
void
|
|
read(std::basic_istream<CharT, Traits> &is, rld a0, Args &&...args);
|
|
|
|
template <class CharT, class Traits, class ...Args>
|
|
void
|
|
read(std::basic_istream<CharT, Traits> &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>(args)...);
|
|
}
|
|
|
|
template <class CharT, class Traits, class ...Args>
|
|
void
|
|
read(std::basic_istream<CharT, Traits> &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>(args)...);
|
|
}
|
|
|
|
template <class CharT, class Traits, class ...Args>
|
|
void
|
|
read(std::basic_istream<CharT, Traits> &is, ru a0, Args &&...args)
|
|
{
|
|
auto x = read_unsigned(is, a0.m, a0.M);
|
|
if (is.fail()) {
|
|
return;
|
|
}
|
|
a0.i = static_cast<int>(x);
|
|
read(is, std::forward<Args>(args)...);
|
|
}
|
|
|
|
template <class CharT, class Traits, class ...Args>
|
|
void
|
|
read(std::basic_istream<CharT, Traits> &is, int a0, Args &&...args)
|
|
{
|
|
if (a0 != -1) {
|
|
auto u = static_cast<unsigned>(a0);
|
|
CharT buf[std::numeric_limits<unsigned>::digits10 + 2] = {};
|
|
auto e = buf;
|
|
do {
|
|
*e++ = static_cast<CharT>(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>(args)...);
|
|
}
|
|
}
|
|
|
|
template <class CharT, class Traits, class ...Args>
|
|
void
|
|
read(std::basic_istream<CharT, Traits> &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>(args)...);
|
|
}
|
|
|
|
template <class T, class CharT, class Traits>
|
|
inline
|
|
void
|
|
checked_set(T &value, T from, T not_a_value, std::basic_ios<CharT, Traits> &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 <class CharT, class Traits, class Duration, class Alloc = std::allocator<CharT>>
|
|
std::basic_istream<CharT, Traits> &
|
|
from_stream(std::basic_istream<CharT, Traits> &is, const CharT *fmt,
|
|
fields<Duration> &fds, std::basic_string<CharT, Traits, Alloc> *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<CharT, Traits>::sentry ok{is, true};
|
|
if (ok) {
|
|
date::detail::save_istream<CharT, Traits> ss(is);
|
|
is.fill(' ');
|
|
is.flags(std::ios::skipws | std::ios::dec);
|
|
is.width(0);
|
|
#if !ONLY_C_LOCALE
|
|
auto &f = std::use_facet<std::time_get<CharT>>(is.getloc());
|
|
std::tm tm{};
|
|
#endif
|
|
const CharT *command = nullptr;
|
|
auto modified = CharT{};
|
|
auto width = -1;
|
|
|
|
CONSTDATA int not_a_year = numeric_limits<int>::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<int>::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<CharT, Traits, Alloc> 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<unsigned>(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<Duration>(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<int>(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<int>(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<Duration>;
|
|
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>(duration<long double> {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<Duration>(seconds{tm.tm_sec}),
|
|
not_a_second, is);
|
|
}
|
|
is.setstate(err);
|
|
#else
|
|
// "%T"
|
|
using dfs = detail::decimal_format_seconds<Duration>;
|
|
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>(duration<long double> {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<unsigned>(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<unsigned>(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<unsigned>(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<unsigned>(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<unsigned>(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<unsigned>(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<unsigned>(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<unsigned>(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<Duration>(seconds{tm.tm_sec}),
|
|
not_a_second, is);
|
|
}
|
|
is.setstate(err);
|
|
#else
|
|
// "%I:%M:%S %p"
|
|
using dfs = detail::decimal_format_seconds<Duration>;
|
|
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>(duration<long double> {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<int>(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<Duration>;
|
|
CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width;
|
|
long double S;
|
|
read(is, rld{S, 1, width == -1 ? w : static_cast<unsigned>(width)});
|
|
checked_set(s, round<Duration>(duration<long double> {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<Duration>(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<Duration>;
|
|
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>(duration<long double> {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<unsigned>(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<unsigned>(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<unsigned>(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<unsigned>(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<unsigned>(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<unsigned>(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<unsigned>(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<char>(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<char>(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<char>(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<CharT, Traits, Alloc> 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<char>(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<char>(*fmt) - '0';
|
|
while ('0' <= fmt[1] && fmt[1] <= '9') {
|
|
width = 10 * width + static_cast<char>(*++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<unsigned char>(*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<int>(year::min()) || Y > static_cast<int>(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<unsigned>(wd)} -Monday);
|
|
if (Y == not_a_year) {
|
|
Y = static_cast<int>(ymd_trial.year());
|
|
}
|
|
else if (year{Y} != ymd_trial.year())
|
|
goto broken;
|
|
if (m == not_a_month) {
|
|
m = static_cast<int>(static_cast<unsigned>(ymd_trial.month()));
|
|
}
|
|
else if (month(static_cast<unsigned>(m)) != ymd_trial.month()) {
|
|
goto broken;
|
|
}
|
|
if (d == not_a_day) {
|
|
d = static_cast<int>(static_cast<unsigned>(ymd_trial.day()));
|
|
}
|
|
else if (day(static_cast<unsigned>(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<unsigned>(wd)} - Sunday);
|
|
if (Y == not_a_year) {
|
|
Y = static_cast<int>(ymd_trial.year());
|
|
}
|
|
else if (year{Y} != ymd_trial.year())
|
|
goto broken;
|
|
if (m == not_a_month) {
|
|
m = static_cast<int>(static_cast<unsigned>(ymd_trial.month()));
|
|
}
|
|
else if (month(static_cast<unsigned>(m)) != ymd_trial.month()) {
|
|
goto broken;
|
|
}
|
|
if (d == not_a_day) {
|
|
d = static_cast<int>(static_cast<unsigned>(ymd_trial.day()));
|
|
}
|
|
else if (day(static_cast<unsigned>(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<unsigned>(wd)} - Monday);
|
|
if (Y == not_a_year) {
|
|
Y = static_cast<int>(ymd_trial.year());
|
|
}
|
|
else if (year{Y} != ymd_trial.year())
|
|
goto broken;
|
|
if (m == not_a_month) {
|
|
m = static_cast<int>(static_cast<unsigned>(ymd_trial.month()));
|
|
}
|
|
else if (month(static_cast<unsigned>(m)) != ymd_trial.month()) {
|
|
goto broken;
|
|
}
|
|
if (d == not_a_day) {
|
|
d = static_cast<int>(static_cast<unsigned>(ymd_trial.day()));
|
|
}
|
|
else if (day(static_cast<unsigned>(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<int>(static_cast<unsigned>(ymd_trial.month()));
|
|
}
|
|
else if (month(static_cast<unsigned>(m)) != ymd_trial.month()) {
|
|
goto broken;
|
|
}
|
|
if (d == 0) {
|
|
d = static_cast<int>(static_cast<unsigned>(ymd_trial.day()));
|
|
}
|
|
else if (day(static_cast<unsigned>(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<int>((weekday(sys_days(ymd)) - Sunday).count());
|
|
}
|
|
else if (wd != static_cast<int>((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<int>(G_trial)) {
|
|
goto broken;
|
|
}
|
|
if (V != not_a_week_num) {
|
|
auto V_trial = duration_cast<weeks>(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<weeks>(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<weeks>(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<Duration> {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<Duration> {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<unsigned>(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 <class CharT, class Traits, class Alloc = std::allocator<CharT>>
|
|
std::basic_istream<CharT, Traits> &
|
|
from_stream(std::basic_istream<CharT, Traits> &is, const CharT *fmt, year &y,
|
|
std::basic_string<CharT, Traits, Alloc> *abbrev = nullptr,
|
|
std::chrono::minutes *offset = nullptr)
|
|
{
|
|
using CT = std::chrono::seconds;
|
|
fields<CT> 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 <class CharT, class Traits, class Alloc = std::allocator<CharT>>
|
|
std::basic_istream<CharT, Traits> &
|
|
from_stream(std::basic_istream<CharT, Traits> &is, const CharT *fmt, month &m,
|
|
std::basic_string<CharT, Traits, Alloc> *abbrev = nullptr,
|
|
std::chrono::minutes *offset = nullptr)
|
|
{
|
|
using CT = std::chrono::seconds;
|
|
fields<CT> 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 <class CharT, class Traits, class Alloc = std::allocator<CharT>>
|
|
std::basic_istream<CharT, Traits> &
|
|
from_stream(std::basic_istream<CharT, Traits> &is, const CharT *fmt, day &d,
|
|
std::basic_string<CharT, Traits, Alloc> *abbrev = nullptr,
|
|
std::chrono::minutes *offset = nullptr)
|
|
{
|
|
using CT = std::chrono::seconds;
|
|
fields<CT> 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 <class CharT, class Traits, class Alloc = std::allocator<CharT>>
|
|
std::basic_istream<CharT, Traits> &
|
|
from_stream(std::basic_istream<CharT, Traits> &is, const CharT *fmt,
|
|
weekday &wd,
|
|
std::basic_string<CharT, Traits, Alloc> *abbrev = nullptr,
|
|
std::chrono::minutes *offset = nullptr)
|
|
{
|
|
using CT = std::chrono::seconds;
|
|
fields<CT> 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 <class CharT, class Traits, class Alloc = std::allocator<CharT>>
|
|
std::basic_istream<CharT, Traits> &
|
|
from_stream(std::basic_istream<CharT, Traits> &is, const CharT *fmt,
|
|
year_month &ym,
|
|
std::basic_string<CharT, Traits, Alloc> *abbrev = nullptr,
|
|
std::chrono::minutes *offset = nullptr)
|
|
{
|
|
using CT = std::chrono::seconds;
|
|
fields<CT> 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 <class CharT, class Traits, class Alloc = std::allocator<CharT>>
|
|
std::basic_istream<CharT, Traits> &
|
|
from_stream(std::basic_istream<CharT, Traits> &is, const CharT *fmt,
|
|
month_day &md,
|
|
std::basic_string<CharT, Traits, Alloc> *abbrev = nullptr,
|
|
std::chrono::minutes *offset = nullptr)
|
|
{
|
|
using CT = std::chrono::seconds;
|
|
fields<CT> 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 <class CharT, class Traits, class Alloc = std::allocator<CharT>>
|
|
std::basic_istream<CharT, Traits> &
|
|
from_stream(std::basic_istream<CharT, Traits> &is, const CharT *fmt,
|
|
year_month_day &ymd, std::basic_string<CharT, Traits, Alloc> *abbrev = nullptr,
|
|
std::chrono::minutes *offset = nullptr)
|
|
{
|
|
using CT = std::chrono::seconds;
|
|
fields<CT> 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 <class Duration, class CharT, class Traits, class Alloc = std::allocator<CharT>>
|
|
std::basic_istream<CharT, Traits> &
|
|
from_stream(std::basic_istream<CharT, Traits> &is, const CharT *fmt,
|
|
sys_time<Duration> &tp, std::basic_string<CharT, Traits, Alloc> *abbrev =
|
|
nullptr,
|
|
std::chrono::minutes *offset = nullptr)
|
|
{
|
|
using CT = typename std::common_type<Duration, std::chrono::seconds>::type;
|
|
std::chrono::minutes offset_local{};
|
|
auto offptr = offset ? offset : &offset_local;
|
|
fields<CT> 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<Duration>(sys_days(fds.ymd) - *offptr + fds.tod.to_duration());
|
|
}
|
|
return is;
|
|
}
|
|
|
|
template <class Duration, class CharT, class Traits, class Alloc = std::allocator<CharT>>
|
|
std::basic_istream<CharT, Traits> &
|
|
from_stream(std::basic_istream<CharT, Traits> &is, const CharT *fmt,
|
|
local_time<Duration> &tp,
|
|
std::basic_string<CharT, Traits, Alloc> *abbrev = nullptr,
|
|
std::chrono::minutes *offset = nullptr)
|
|
{
|
|
using CT = typename std::common_type<Duration, std::chrono::seconds>::type;
|
|
fields<CT> 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<Duration>(local_seconds{local_days(fds.ymd)} +
|
|
fds.tod.to_duration());
|
|
return is;
|
|
}
|
|
|
|
template <class Rep, class Period, class CharT, class Traits, class Alloc = std::allocator<CharT>>
|
|
std::basic_istream<CharT, Traits> &
|
|
from_stream(std::basic_istream<CharT, Traits> &is, const CharT *fmt,
|
|
std::chrono::duration<Rep, Period> &d,
|
|
std::basic_string<CharT, Traits, Alloc> *abbrev = nullptr,
|
|
std::chrono::minutes *offset = nullptr)
|
|
{
|
|
using Duration = std::chrono::duration<Rep, Period>;
|
|
using CT = typename std::common_type<Duration, std::chrono::seconds>::type;
|
|
fields<CT> 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<Duration>(fds.tod.to_duration());
|
|
}
|
|
return is;
|
|
}
|
|
|
|
template <class Parsable, class CharT, class Traits = std::char_traits<CharT>,
|
|
class Alloc = std::allocator<CharT>>
|
|
struct parse_manip {
|
|
const std::basic_string<CharT, Traits, Alloc> format_;
|
|
Parsable &tp_;
|
|
std::basic_string<CharT, Traits, Alloc> *abbrev_;
|
|
std::chrono::minutes *offset_;
|
|
|
|
public:
|
|
parse_manip(std::basic_string<CharT, Traits, Alloc> format, Parsable &tp,
|
|
std::basic_string<CharT, Traits, Alloc> *abbrev = nullptr,
|
|
std::chrono::minutes *offset = nullptr)
|
|
: format_(std::move(format))
|
|
, tp_(tp)
|
|
, abbrev_(abbrev)
|
|
, offset_(offset)
|
|
{}
|
|
|
|
};
|
|
|
|
template <class Parsable, class CharT, class Traits, class Alloc>
|
|
std::basic_istream<CharT, Traits> &
|
|
operator>>(std::basic_istream<CharT, Traits> &is,
|
|
const parse_manip<Parsable, CharT, Traits, Alloc> &x)
|
|
{
|
|
return from_stream(is, x.format_.c_str(), x.tp_, x.abbrev_, x.offset_);
|
|
}
|
|
|
|
template <class Parsable, class CharT, class Traits, class Alloc>
|
|
inline
|
|
auto
|
|
parse(const std::basic_string<CharT, Traits, Alloc> &format, Parsable &tp)
|
|
-> decltype(from_stream(std::declval<std::basic_istream<CharT, Traits>&>(),
|
|
format.c_str(), tp),
|
|
parse_manip<Parsable, CharT, Traits, Alloc>
|
|
{
|
|
format, tp
|
|
})
|
|
{
|
|
return {format, tp};
|
|
}
|
|
|
|
template <class Parsable, class CharT, class Traits, class Alloc>
|
|
inline
|
|
auto
|
|
parse(const std::basic_string<CharT, Traits, Alloc> &format, Parsable &tp,
|
|
std::basic_string<CharT, Traits, Alloc> &abbrev)
|
|
-> decltype(from_stream(std::declval<std::basic_istream<CharT, Traits>&>(),
|
|
format.c_str(), tp, &abbrev),
|
|
parse_manip<Parsable, CharT, Traits, Alloc>
|
|
{
|
|
format, tp, &abbrev
|
|
})
|
|
{
|
|
return {format, tp, &abbrev};
|
|
}
|
|
|
|
template <class Parsable, class CharT, class Traits, class Alloc>
|
|
inline
|
|
auto
|
|
parse(const std::basic_string<CharT, Traits, Alloc> &format, Parsable &tp,
|
|
std::chrono::minutes &offset)
|
|
-> decltype(from_stream(std::declval<std::basic_istream<CharT, Traits>&>(),
|
|
format.c_str(), tp,
|
|
std::declval<std::basic_string<CharT, Traits, Alloc>*>(),
|
|
&offset),
|
|
parse_manip<Parsable, CharT, Traits, Alloc>
|
|
{
|
|
format, tp, nullptr, &offset
|
|
})
|
|
{
|
|
return {format, tp, nullptr, &offset};
|
|
}
|
|
|
|
template <class Parsable, class CharT, class Traits, class Alloc>
|
|
inline
|
|
auto
|
|
parse(const std::basic_string<CharT, Traits, Alloc> &format, Parsable &tp,
|
|
std::basic_string<CharT, Traits, Alloc> &abbrev, std::chrono::minutes &offset)
|
|
-> decltype(from_stream(std::declval<std::basic_istream<CharT, Traits>&>(),
|
|
format.c_str(), tp, &abbrev, &offset),
|
|
parse_manip<Parsable, CharT, Traits, Alloc>
|
|
{
|
|
format, tp, &abbrev, &offset
|
|
})
|
|
{
|
|
return {format, tp, &abbrev, &offset};
|
|
}
|
|
|
|
// const CharT* formats
|
|
|
|
template <class Parsable, class CharT>
|
|
inline
|
|
auto
|
|
parse(const CharT *format, Parsable &tp)
|
|
-> decltype(from_stream(std::declval<std::basic_istream<CharT>&>(), format, tp),
|
|
parse_manip<Parsable, CharT>
|
|
{
|
|
format, tp
|
|
})
|
|
{
|
|
return {format, tp};
|
|
}
|
|
|
|
template <class Parsable, class CharT, class Traits, class Alloc>
|
|
inline
|
|
auto
|
|
parse(const CharT *format, Parsable &tp,
|
|
std::basic_string<CharT, Traits, Alloc> &abbrev)
|
|
-> decltype(from_stream(std::declval<std::basic_istream<CharT, Traits>&>(),
|
|
format,
|
|
tp, &abbrev),
|
|
parse_manip<Parsable, CharT, Traits, Alloc>
|
|
{
|
|
format, tp, &abbrev
|
|
})
|
|
{
|
|
return {format, tp, &abbrev};
|
|
}
|
|
|
|
template <class Parsable, class CharT>
|
|
inline
|
|
auto
|
|
parse(const CharT *format, Parsable &tp, std::chrono::minutes &offset)
|
|
-> decltype(from_stream(std::declval<std::basic_istream<CharT>&>(), format,
|
|
tp, std::declval<std::basic_string<CharT>*>(), &offset),
|
|
parse_manip<Parsable, CharT>
|
|
{
|
|
format, tp, nullptr, &offset
|
|
})
|
|
{
|
|
return {format, tp, nullptr, &offset};
|
|
}
|
|
|
|
template <class Parsable, class CharT, class Traits, class Alloc>
|
|
inline
|
|
auto
|
|
parse(const CharT *format, Parsable &tp,
|
|
std::basic_string<CharT, Traits, Alloc> &abbrev, std::chrono::minutes &offset)
|
|
-> decltype(from_stream(std::declval<std::basic_istream<CharT, Traits>&>(),
|
|
format,
|
|
tp, &abbrev, &offset),
|
|
parse_manip<Parsable, CharT, Traits, Alloc>
|
|
{
|
|
format, tp, &abbrev, &offset
|
|
})
|
|
{
|
|
return {format, tp, &abbrev, &offset};
|
|
}
|
|
|
|
// duration streaming
|
|
|
|
template <class CharT, class Traits, class Rep, class Period>
|
|
inline
|
|
std::basic_ostream<CharT, Traits> &
|
|
operator<<(std::basic_ostream<CharT, Traits> &os,
|
|
const std::chrono::duration<Rep, Period> &d)
|
|
{
|
|
return os << detail::make_string<CharT, Traits>::from(d.count()) +
|
|
detail::get_units<CharT>(typename Period::type{});
|
|
}
|
|
|
|
} // namespace date
|
|
|
|
#ifdef _MSC_VER
|
|
# pragma warning(pop)
|
|
#endif
|
|
|
|
#ifdef __GNUC__
|
|
# pragma GCC diagnostic pop
|
|
#endif
|
|
|
|
#endif // DATE_H
|
|
|