diff --git a/.github/workflows/github-actions.yml b/.github/workflows/github-actions.yml index 9faa6c29..4f36fc56 100644 --- a/.github/workflows/github-actions.yml +++ b/.github/workflows/github-actions.yml @@ -251,6 +251,7 @@ jobs: env: CIBW_BUILD: cp38-macosx_* cp39-macosx_* cp310-macosx_* cp311-macosx_* cp312-macosx_* cp313-macosx_* CIBW_ARCHS: auto64 + MACOSX_DEPLOYMENT_TARGET: 10.14 CIBW_BEFORE_ALL: > brew install boost swig && git clone https://github.com/F2I-Consulting/Minizip.git ${{ github.workspace }}/../minizip && diff --git a/src/tools/date.h b/src/tools/date.h index d8fb7f26..beb627e4 100644 --- a/src/tools/date.h +++ b/src/tools/date.h @@ -45,9 +45,7 @@ #include #include #include -#if !(__cplusplus >= 201402) -# include -#endif +#include #include #include #include @@ -138,7 +136,7 @@ namespace date #endif #ifndef HAS_UNCAUGHT_EXCEPTIONS -# if __cplusplus > 201703 || (defined(_MSVC_LANG) && _MSVC_LANG > 201703L) +# if __cplusplus >= 201703 || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) # define HAS_UNCAUGHT_EXCEPTIONS 1 # else # define HAS_UNCAUGHT_EXCEPTIONS 0 @@ -418,8 +416,8 @@ class year 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}; } + 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; @@ -1006,6 +1004,8 @@ struct is_clock inline constexpr bool is_clock_v = is_clock::value; + #endif // HAS_VOID_T //----------------+ @@ -1022,6 +1022,7 @@ class save_istream std::basic_ios& is_; CharT fill_; std::ios::fmtflags flags_; + std::streamsize precision_; std::streamsize width_; std::basic_ostream* tie_; std::locale loc_; @@ -1031,6 +1032,7 @@ class save_istream { is_.fill(fill_); is_.flags(flags_); + is_.precision(precision_); is_.width(width_); is_.imbue(loc_); is_.tie(tie_); @@ -1043,6 +1045,7 @@ class save_istream : is_(is) , fill_(is.fill()) , flags_(is.flags()) + , precision_(is.precision()) , width_(is.width(0)) , tie_(is.tie(nullptr)) , loc_(is.getloc()) @@ -1166,7 +1169,11 @@ struct no_overflow static const std::intmax_t d1 = R1::den / gcd_d1_d2; static const std::intmax_t n2 = R2::num / gcd_n1_n2; static const std::intmax_t d2 = R2::den / gcd_d1_d2; - static const std::intmax_t max = (std::numeric_limits::max)(); +#ifdef __cpp_constexpr + static const std::intmax_t max = std::numeric_limits::max(); +#else + static const std::intmax_t max = LLONG_MAX; +#endif template struct mul // overflow == false @@ -1309,7 +1316,7 @@ CONSTCD11 std::chrono::duration abs(std::chrono::duration d) { - return d >= d.zero() ? d : -d; + return d >= d.zero() ? d : static_cast(-d); } // round down @@ -1354,6 +1361,47 @@ using std::chrono::abs; #endif // HAS_CHRONO_ROUNDING +namespace detail +{ + +template +CONSTCD14 +inline +typename std::enable_if +< + !std::chrono::treat_as_floating_point::value, + To +>::type +round_i(const std::chrono::duration& d) +{ + return round(d); +} + +template +CONSTCD14 +inline +typename std::enable_if +< + std::chrono::treat_as_floating_point::value, + To +>::type +round_i(const std::chrono::duration& d) +{ + return d; +} + +template +CONSTCD11 +inline +std::chrono::time_point +round_i(const std::chrono::time_point& tp) +{ + using std::chrono::time_point; + return time_point{round_i(tp.time_since_epoch())}; +} + +} // detail + // trunc towards zero template CONSTCD11 @@ -1458,16 +1506,29 @@ operator-(const day& x, const days& y) NOEXCEPT return x + -y; } +namespace detail +{ + template -inline std::basic_ostream& -operator<<(std::basic_ostream& os, const day& d) +low_level_fmt(std::basic_ostream& os, const day& d) { detail::save_ostream _(os); os.fill('0'); os.flags(std::ios::dec | std::ios::right); os.width(2); os << static_cast(d); + return os; +} + +} // namespace detail + +template +inline +std::basic_ostream& +operator<<(std::basic_ostream& os, const day& d) +{ + detail::low_level_fmt(os, d); if (!d.ok()) os << " is not a valid day"; return os; @@ -1585,10 +1646,12 @@ operator-(const month& x, const months& y) NOEXCEPT return x + -y; } +namespace detail +{ + template -inline std::basic_ostream& -operator<<(std::basic_ostream& os, const month& m) +low_level_fmt(std::basic_ostream& os, const month& m) { if (m.ok()) { @@ -1596,7 +1659,20 @@ operator<<(std::basic_ostream& os, const month& m) os << format(os.getloc(), fmt, m); } else - os << static_cast(m) << " is not a valid month"; + os << static_cast(m); + return os; +} + +} // namespace detail + +template +inline +std::basic_ostream& +operator<<(std::basic_ostream& os, const month& m) +{ + detail::low_level_fmt(os, m); + if (!m.ok()) + os << " is not a valid month"; return os; } @@ -1627,7 +1703,7 @@ inline bool year::ok() const NOEXCEPT { - return y_ != (std::numeric_limits::min)(); + return y_ != std::numeric_limits::min(); } CONSTCD11 @@ -1710,10 +1786,12 @@ operator-(const year& x, const years& y) NOEXCEPT return year{static_cast(x) - y.count()}; } +namespace detail +{ + template -inline std::basic_ostream& -operator<<(std::basic_ostream& os, const year& y) +low_level_fmt(std::basic_ostream& os, const year& y) { detail::save_ostream _(os); os.fill('0'); @@ -1721,6 +1799,17 @@ operator<<(std::basic_ostream& os, const year& y) os.width(4 + (y < year{0})); os.imbue(std::locale::classic()); os << static_cast(y); + return os; +} + +} // namespace detail + +template +inline +std::basic_ostream& +operator<<(std::basic_ostream& os, const year& y) +{ + detail::low_level_fmt(os, y); if (!y.ok()) os << " is not a valid year"; return os; @@ -1846,10 +1935,12 @@ operator-(const weekday& x, const days& y) NOEXCEPT return x + -y; } +namespace detail +{ + template -inline std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday& wd) +low_level_fmt(std::basic_ostream& os, const weekday& wd) { if (wd.ok()) { @@ -1857,7 +1948,20 @@ operator<<(std::basic_ostream& os, const weekday& wd) os << format(fmt, wd); } else - os << static_cast(wd.wd_) << " is not a valid weekday"; + os << wd.c_encoding(); + return os; +} + +} // namespace detail + +template +inline +std::basic_ostream& +operator<<(std::basic_ostream& os, const weekday& wd) +{ + detail::low_level_fmt(os, wd); + if (!wd.ok()) + os << " is not a valid weekday"; return os; } @@ -1966,15 +2070,26 @@ weekday_indexed::weekday_indexed(const date::weekday& wd, unsigned index) NOEXCE # pragma GCC diagnostic pop #endif // __GNUC__ +namespace detail +{ + +template +std::basic_ostream& +low_level_fmt(std::basic_ostream& os, const weekday_indexed& wdi) +{ + return low_level_fmt(os, wdi.weekday()) << '[' << wdi.index() << ']'; +} + +} // namespace detail + template inline std::basic_ostream& operator<<(std::basic_ostream& os, const weekday_indexed& wdi) { - os << wdi.weekday() << '[' << wdi.index(); - if (!(1 <= wdi.index() && wdi.index() <= 5)) - os << " is not a valid index"; - os << ']'; + detail::low_level_fmt(os, wdi); + if (!wdi.ok()) + os << " is not a valid weekday_indexed"; return os; } @@ -2024,12 +2139,27 @@ operator!=(const weekday_last& x, const weekday_last& y) NOEXCEPT return !(x == y); } +namespace detail +{ + +template +std::basic_ostream& +low_level_fmt(std::basic_ostream& os, const weekday_last& wdl) +{ + return low_level_fmt(os, wdl.weekday()) << "[last]"; +} + +} // namespace detail + template inline std::basic_ostream& operator<<(std::basic_ostream& os, const weekday_last& wdl) { - return os << wdl.weekday() << "[last]"; + detail::low_level_fmt(os, wdl); + if (!wdl.ok()) + os << " is not a valid weekday_last"; + return os; } CONSTCD11 @@ -2204,12 +2334,28 @@ operator-(const year_month& ym, const years& dy) NOEXCEPT return ym + -dy; } +namespace detail +{ + +template +std::basic_ostream& +low_level_fmt(std::basic_ostream& os, const year_month& ym) +{ + low_level_fmt(os, ym.year()) << '/'; + return low_level_fmt(os, ym.month()); +} + +} // namespace detail + template inline std::basic_ostream& operator<<(std::basic_ostream& os, const year_month& ym) { - return os << ym.year() << '/' << ym.month(); + detail::low_level_fmt(os, ym); + if (!ym.ok()) + os << " is not a valid year_month"; + return os; } // month_day @@ -2289,12 +2435,28 @@ operator>=(const month_day& x, const month_day& y) NOEXCEPT return !(x < y); } +namespace detail +{ + +template +std::basic_ostream& +low_level_fmt(std::basic_ostream& os, const month_day& md) +{ + low_level_fmt(os, md.month()) << '/'; + return low_level_fmt(os, md.day()); +} + +} // namespace detail + template inline std::basic_ostream& operator<<(std::basic_ostream& os, const month_day& md) { - return os << md.month() << '/' << md.day(); + detail::low_level_fmt(os, md); + if (!md.ok()) + os << " is not a valid month_day"; + return os; } // month_day_last @@ -2351,12 +2513,27 @@ operator>=(const month_day_last& x, const month_day_last& y) NOEXCEPT return !(x < y); } +namespace detail +{ + +template +std::basic_ostream& +low_level_fmt(std::basic_ostream& os, const month_day_last& mdl) +{ + return low_level_fmt(os, mdl.month()) << "/last"; +} + +} // namespace detail + template inline std::basic_ostream& operator<<(std::basic_ostream& os, const month_day_last& mdl) { - return os << mdl.month() << "/last"; + detail::low_level_fmt(os, mdl); + if (!mdl.ok()) + os << " is not a valid month_day_last"; + return os; } // month_weekday @@ -2403,12 +2580,28 @@ operator!=(const month_weekday& x, const month_weekday& y) NOEXCEPT return !(x == y); } +namespace detail +{ + +template +std::basic_ostream& +low_level_fmt(std::basic_ostream& os, const month_weekday& mwd) +{ + low_level_fmt(os, mwd.month()) << '/'; + return low_level_fmt(os, mwd.weekday_indexed()); +} + +} // namespace detail + template inline std::basic_ostream& operator<<(std::basic_ostream& os, const month_weekday& mwd) { - return os << mwd.month() << '/' << mwd.weekday_indexed(); + detail::low_level_fmt(os, mwd); + if (!mwd.ok()) + os << " is not a valid month_weekday"; + return os; } // month_weekday_last @@ -2455,12 +2648,28 @@ operator!=(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT return !(x == y); } +namespace detail +{ + +template +std::basic_ostream& +low_level_fmt(std::basic_ostream& os, const month_weekday_last& mwdl) +{ + low_level_fmt(os, mwdl.month()) << '/'; + return low_level_fmt(os, mwdl.weekday_last()); +} + +} // namespace detail + template inline std::basic_ostream& operator<<(std::basic_ostream& os, const month_weekday_last& mwdl) { - return os << mwdl.month() << '/' << mwdl.weekday_last(); + detail::low_level_fmt(os, mwdl); + if (!mwdl.ok()) + os << " is not a valid month_weekday_last"; + return os; } // year_month_day_last @@ -2610,12 +2819,28 @@ operator>=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT return !(x < y); } +namespace detail +{ + +template +std::basic_ostream& +low_level_fmt(std::basic_ostream& os, const year_month_day_last& ymdl) +{ + low_level_fmt(os, ymdl.year()) << '/'; + return low_level_fmt(os, ymdl.month_day_last()); +} + +} // namespace detail + template inline std::basic_ostream& operator<<(std::basic_ostream& os, const year_month_day_last& ymdl) { - return os << ymdl.year() << '/' << ymdl.month_day_last(); + detail::low_level_fmt(os, ymdl); + if (!ymdl.ok()) + os << " is not a valid year_month_day_last"; + return os; } template @@ -2846,12 +3071,13 @@ operator<<(std::basic_ostream& os, const year_month_day& ymd) os.fill('0'); os.flags(std::ios::dec | std::ios::right); os.imbue(std::locale::classic()); - os << ymd.year() << '-'; + os << static_cast(ymd.year()) << '-'; os.width(2); os << static_cast(ymd.month()) << '-'; - os << ymd.day(); + os.width(2); + os << static_cast(ymd.day()); if (!ymd.ok()) - os << " is not a valid date"; + os << " is not a valid year_month_day"; return os; } @@ -3087,8 +3313,12 @@ inline std::basic_ostream& operator<<(std::basic_ostream& os, const year_month_weekday& ymwdi) { - return os << ymwdi.year() << '/' << ymwdi.month() - << '/' << ymwdi.weekday_indexed(); + detail::low_level_fmt(os, ymwdi.year()) << '/'; + detail::low_level_fmt(os, ymwdi.month()) << '/'; + detail::low_level_fmt(os, ymwdi.weekday_indexed()); + if (!ymwdi.ok()) + os << " is not a valid year_month_weekday"; + return os; } template @@ -3264,7 +3494,12 @@ inline std::basic_ostream& operator<<(std::basic_ostream& os, const year_month_weekday_last& ymwdl) { - return os << ymwdl.year() << '/' << ymwdl.month() << '/' << ymwdl.weekday_last(); + detail::low_level_fmt(os, ymwdl.year()) << '/'; + detail::low_level_fmt(os, ymwdl.month()) << '/'; + detail::low_level_fmt(os, ymwdl.weekday_last()); + if (!ymwdl.ok()) + os << " is not a valid year_month_weekday_last"; + return os; } template @@ -3681,11 +3916,12 @@ struct undocumented {explicit undocumented() = default;}; // Example: width<4>::value == 2 // Example: width<10>::value == 1 // Example: width<1000>::value == 3 -template +template struct width { - static CONSTDATA unsigned value = 1 + width::value; + static_assert(d > 0, "width called with zero denominator"); + static CONSTDATA unsigned value = 1 + width::value; }; template @@ -3714,9 +3950,10 @@ class decimal_format_seconds { using CT = typename std::common_type::type; using rep = typename CT::rep; + static unsigned CONSTDATA trial_width = + detail::width::value; public: - static unsigned constexpr width = detail::width::value < 19 ? - detail::width::value : 6u; + static unsigned CONSTDATA width = trial_width < 19 ? trial_width : 6u; using precision = std::chrono::duration::value>>; @@ -3765,6 +4002,7 @@ class decimal_format_seconds std::chrono::duration d = s_ + sub_s_; if (d < std::chrono::seconds{10}) os << '0'; + os.precision(width+6); os << std::fixed << d.count(); return os; } @@ -3955,9 +4193,7 @@ make24(std::chrono::hours h, bool is_pm) NOEXCEPT template using time_of_day = hh_mm_ss; -template ::value>::type> +template CONSTCD11 inline hh_mm_ss> @@ -3970,9 +4206,8 @@ template inline typename std::enable_if < - !std::chrono::treat_as_floating_point::value && - std::ratio_less::value - , std::basic_ostream& + !std::is_convertible::value, + std::basic_ostream& >::type operator<<(std::basic_ostream& os, const sys_time& tp) { @@ -3993,7 +4228,7 @@ inline std::basic_ostream& operator<<(std::basic_ostream& os, const local_time& ut) { - return (os << sys_time{ut.time_since_epoch()}); + return (date::operator<<(os, sys_time{ut.time_since_epoch()})); } namespace detail @@ -4552,7 +4787,11 @@ struct fields hh_mm_ss tod{}; bool has_tod = false; +#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ <= 409) + fields() : ymd{nanyear/0/0}, wd{8u}, tod{}, has_tod{false} {} +#else fields() = default; +#endif fields(year_month_day ymd_) : ymd(ymd_) {} fields(weekday wd_) : wd(wd_) {} @@ -4734,7 +4973,7 @@ scan_keyword(std::basic_istream& is, FwdIter kb, FwdIter ke) is.setstate(std::ios::eofbit); break; } - auto c = static_cast(toupper(ic)); + auto c = static_cast(toupper(static_cast(ic))); bool consume = false; // For each keyword which might match, see if the indx character is c // If a match if found, consume c @@ -4747,7 +4986,7 @@ scan_keyword(std::basic_istream& is, FwdIter kb, FwdIter ke) { if (*st == might_match) { - if (c == static_cast(toupper((*ky)[indx]))) + if (c == static_cast(toupper(static_cast((*ky)[indx])))) { consume = true; if (ky->size() == indx+1) @@ -5974,8 +6213,13 @@ to_stream(std::basic_ostream& os, const CharT* fmt, const std::chrono::seconds* offset_sec = nullptr) { using CT = typename std::common_type::type; - auto ld = floor(tp); - fields fds{year_month_day{ld}, hh_mm_ss{tp-local_seconds{ld}}}; + auto ld = std::chrono::time_point_cast(tp); + fields fds; + if (ld <= tp) + fds = fields{year_month_day{ld}, hh_mm_ss{tp-local_seconds{ld}}}; + else + fds = fields{year_month_day{ld - days{1}}, + hh_mm_ss{days{1} - (local_seconds{ld} - tp)}}; return to_stream(os, fmt, fds, abbrev, offset_sec); } @@ -5988,8 +6232,13 @@ to_stream(std::basic_ostream& os, const CharT* fmt, using CT = typename std::common_type::type; const std::string abbrev("UTC"); CONSTDATA seconds offset{0}; - auto sd = floor(tp); - fields fds{year_month_day{sd}, hh_mm_ss{tp-sys_seconds{sd}}}; + auto sd = std::chrono::time_point_cast(tp); + fields fds; + if (sd <= tp) + fds = fields{year_month_day{sd}, hh_mm_ss{tp-sys_seconds{sd}}}; + else + fds = fields{year_month_day{sd - days{1}}, + hh_mm_ss{days{1} - (sys_seconds{sd} - tp)}}; return to_stream(os, fmt, fds, &abbrev, &offset); } @@ -6102,8 +6351,11 @@ read_signed(std::basic_istream& is, unsigned m = 1, unsigned M = if (('0' <= c && c <= '9') || c == '-' || c == '+') { if (c == '-' || c == '+') + { (void)is.get(); - auto x = static_cast(read_unsigned(is, (std::max)(m, 1u), M)); + --M; + } + auto x = static_cast(read_unsigned(is, std::max(m, 1u), M)); if (!is.fail()) { if (c == '-') @@ -6122,9 +6374,16 @@ long double read_long_double(std::basic_istream& is, unsigned m = 1, unsigned M = 10) { unsigned count = 0; + unsigned fcount = 0; + unsigned long long i = 0; + unsigned long long f = 0; + bool parsing_fraction = false; +#if ONLY_C_LOCALE + typename Traits::int_type decimal_point = '.'; +#else auto decimal_point = Traits::to_int_type( std::use_facet>(is.getloc()).decimal_point()); - std::string buf; +#endif while (true) { auto ic = is.peek(); @@ -6132,18 +6391,25 @@ read_long_double(std::basic_istream& is, unsigned m = 1, unsigned break; if (Traits::eq_int_type(ic, decimal_point)) { - buf += '.'; decimal_point = Traits::eof(); - is.get(); + parsing_fraction = true; } else { auto c = static_cast(Traits::to_char_type(ic)); if (!('0' <= c && c <= '9')) break; - buf += c; - (void)is.get(); + if (!parsing_fraction) + { + i = 10*i + static_cast(c - '0'); + } + else + { + f = 10*f + static_cast(c - '0'); + ++fcount; + } } + (void)is.get(); if (++count == M) break; } @@ -6152,7 +6418,7 @@ read_long_double(std::basic_istream& is, unsigned m = 1, unsigned is.setstate(std::ios::failbit); return 0; } - return std::stold(buf); + return static_cast(i) + static_cast(f)/std::pow(10.L, fcount); } struct rs @@ -6261,7 +6527,14 @@ read(std::basic_istream& is, int a0, Args&& ...args) *e++ = static_cast(CharT(u % 10) + CharT{'0'}); u /= 10; } while (u > 0); +#if defined(__GNUC__) && __GNUC__ >= 11 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstringop-overflow" +#endif std::reverse(buf, e); +#if defined(__GNUC__) && __GNUC__ >= 11 +#pragma GCC diagnostic pop +#endif for (auto p = buf; p != e && is.rdstate() == std::ios::goodbit; ++p) read(is, *p); } @@ -6309,6 +6582,7 @@ from_stream(std::basic_istream& is, const CharT* fmt, using std::chrono::seconds; using std::chrono::minutes; using std::chrono::hours; + using detail::round_i; typename std::basic_istream::sentry ok{is, true}; if (ok) { @@ -6324,20 +6598,20 @@ from_stream(std::basic_istream& is, const CharT* fmt, auto modified = CharT{}; auto width = -1; - CONSTDATA int not_a_year = (numeric_limits::min)(); + CONSTDATA int not_a_year = numeric_limits::min(); CONSTDATA int not_a_2digit_year = 100; - CONSTDATA int not_a_century = not_a_year / 100; + CONSTDATA int not_a_century = numeric_limits::min(); CONSTDATA int not_a_month = 0; CONSTDATA int not_a_day = 0; - CONSTDATA int not_a_hour = (numeric_limits::min)(); + CONSTDATA int not_a_hour = numeric_limits::min(); CONSTDATA int not_a_hour_12_value = 0; CONSTDATA int not_a_minute = not_a_hour; - CONSTDATA Duration not_a_second = (Duration::min)(); + CONSTDATA 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)(); + CONSTDATA minutes not_a_offset = minutes::min(); int Y = not_a_year; // c, F, Y * int y = not_a_2digit_year; // D, x, y * @@ -6517,12 +6791,12 @@ from_stream(std::basic_istream& is, const CharT* fmt, CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width; int tH; int tM; - long double S; + long double S{}; read(is, ru{tH, 1, 2}, CharT{':'}, ru{tM, 1, 2}, CharT{':'}, rld{S, 1, w}); checked_set(H, tH, not_a_hour, is); checked_set(M, tM, not_a_minute, is); - checked_set(s, round(duration{S}), + checked_set(s, round_i(duration{S}), not_a_second, is); ws(is); int tY = not_a_year; @@ -6597,12 +6871,12 @@ from_stream(std::basic_istream& is, const CharT* fmt, CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width; int tH = not_a_hour; int tM = not_a_minute; - long double S; + long double S{}; read(is, ru{tH, 1, 2}, CharT{':'}, ru{tM, 1, 2}, CharT{':'}, rld{S, 1, w}); checked_set(H, tH, not_a_hour, is); checked_set(M, tM, not_a_minute, is); - checked_set(s, round(duration{S}), + checked_set(s, round_i(duration{S}), not_a_second, is); #endif } @@ -6918,7 +7192,7 @@ from_stream(std::basic_istream& is, const CharT* fmt, #else auto nm = detail::ampm_names(); auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first; - tp = i; + tp = static_cast(i); #endif checked_set(p, tp, not_a_ampm, is); } @@ -6952,14 +7226,14 @@ from_stream(std::basic_istream& is, const CharT* fmt, // "%I:%M:%S %p" using dfs = detail::decimal_format_seconds; CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width; - long double S; + long double S{}; int tI = not_a_hour_12_value; int tM = not_a_minute; read(is, ru{tI, 1, 2}, CharT{':'}, ru{tM, 1, 2}, CharT{':'}, rld{S, 1, w}); checked_set(I, tI, not_a_hour_12_value, is); checked_set(M, tM, not_a_minute, is); - checked_set(s, round(duration{S}), + checked_set(s, round_i(duration{S}), not_a_second, is); ws(is); auto nm = detail::ampm_names(); @@ -7008,9 +7282,9 @@ from_stream(std::basic_istream& is, const CharT* fmt, { using dfs = detail::decimal_format_seconds; CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width; - long double S; + long double S{}; read(is, rld{S, 1, width == -1 ? w : static_cast(width)}); - checked_set(s, round(duration{S}), + checked_set(s, round_i(duration{S}), not_a_second, is); } #if !ONLY_C_LOCALE @@ -7042,12 +7316,12 @@ from_stream(std::basic_istream& is, const CharT* fmt, CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width; int tH = not_a_hour; int tM = not_a_minute; - long double S; + long double S{}; read(is, ru{tH, 1, 2}, CharT{':'}, ru{tM, 1, 2}, CharT{':'}, rld{S, 1, w}); checked_set(H, tH, not_a_hour, is); checked_set(M, tM, not_a_minute, is); - checked_set(s, round(duration{S}), + checked_set(s, round_i(duration{S}), not_a_second, is); } else @@ -7253,7 +7527,12 @@ from_stream(std::basic_istream& is, const CharT* fmt, { auto c = static_cast(Traits::to_char_type(ic)); if (c == '-') + { neg = true; + (void)is.get(); + } + else if (c == '+') + (void)is.get(); } if (modified == CharT{}) { @@ -7442,7 +7721,7 @@ from_stream(std::basic_istream& is, const CharT* fmt, goto broken; G = tG; } - if (Y < static_cast((year::min)()) || Y > static_cast((year::max)())) + if (Y < static_cast(year::min()) || Y > static_cast(year::max())) Y = not_a_year; bool computed = false; if (G != not_a_year && V != not_a_week_num && wd != not_a_weekday) @@ -7469,9 +7748,7 @@ from_stream(std::basic_istream& is, const CharT* fmt, year_month_day ymd_trial = sys_days(year{Y}/January/Sunday[1]) + weeks{U-1} + (weekday{static_cast(wd)} - Sunday); - if (Y == not_a_year) - Y = static_cast(ymd_trial.year()); - else if (year{Y} != ymd_trial.year()) + if (year{Y} != ymd_trial.year()) goto broken; if (m == not_a_month) m = static_cast(static_cast(ymd_trial.month())); @@ -7488,9 +7765,7 @@ from_stream(std::basic_istream& is, const CharT* fmt, year_month_day ymd_trial = sys_days(year{Y}/January/Monday[1]) + weeks{W-1} + (weekday{static_cast(wd)} - Monday); - if (Y == not_a_year) - Y = static_cast(ymd_trial.year()); - else if (year{Y} != ymd_trial.year()) + if (year{Y} != ymd_trial.year()) goto broken; if (m == not_a_month) m = static_cast(static_cast(ymd_trial.month())); @@ -7505,11 +7780,11 @@ from_stream(std::basic_istream& is, const CharT* fmt, 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) + if (m == not_a_month) m = static_cast(static_cast(ymd_trial.month())); else if (month(static_cast(m)) != ymd_trial.month()) goto broken; - if (d == 0) + if (d == not_a_day) d = static_cast(static_cast(ymd_trial.day())); else if (day(static_cast(d)) != ymd_trial.day()) goto broken; @@ -7595,6 +7870,8 @@ from_stream(std::basic_istream& is, const CharT* fmt, goto broken; } } + else // I is ambiguous, AM or PM? + goto broken; } } if (H != not_a_hour) @@ -7639,7 +7916,7 @@ from_stream(std::basic_istream& is, const CharT* fmt, year& y, { using CT = std::chrono::seconds; fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); + date::from_stream(is, fmt, fds, abbrev, offset); if (!fds.ymd.year().ok()) is.setstate(std::ios::failbit); if (!is.fail()) @@ -7655,7 +7932,7 @@ from_stream(std::basic_istream& is, const CharT* fmt, month& m, { using CT = std::chrono::seconds; fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); + date::from_stream(is, fmt, fds, abbrev, offset); if (!fds.ymd.month().ok()) is.setstate(std::ios::failbit); if (!is.fail()) @@ -7671,7 +7948,7 @@ from_stream(std::basic_istream& is, const CharT* fmt, day& d, { using CT = std::chrono::seconds; fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); + date::from_stream(is, fmt, fds, abbrev, offset); if (!fds.ymd.day().ok()) is.setstate(std::ios::failbit); if (!is.fail()) @@ -7687,7 +7964,7 @@ from_stream(std::basic_istream& is, const CharT* fmt, weekday& wd { using CT = std::chrono::seconds; fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); + date::from_stream(is, fmt, fds, abbrev, offset); if (!fds.wd.ok()) is.setstate(std::ios::failbit); if (!is.fail()) @@ -7703,7 +7980,7 @@ from_stream(std::basic_istream& is, const CharT* fmt, year_month& { using CT = std::chrono::seconds; fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); + date::from_stream(is, fmt, fds, abbrev, offset); if (!fds.ymd.month().ok()) is.setstate(std::ios::failbit); if (!is.fail()) @@ -7719,7 +7996,7 @@ from_stream(std::basic_istream& is, const CharT* fmt, month_day& { using CT = std::chrono::seconds; fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); + date::from_stream(is, fmt, fds, abbrev, offset); if (!fds.ymd.month().ok() || !fds.ymd.day().ok()) is.setstate(std::ios::failbit); if (!is.fail()) @@ -7735,7 +8012,7 @@ from_stream(std::basic_istream& is, const CharT* fmt, { using CT = std::chrono::seconds; fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); + date::from_stream(is, fmt, fds, abbrev, offset); if (!fds.ymd.ok()) is.setstate(std::ios::failbit); if (!is.fail()) @@ -7750,15 +8027,16 @@ from_stream(std::basic_istream& is, const CharT* fmt, std::chrono::minutes* offset = nullptr) { using CT = typename std::common_type::type; + using detail::round_i; std::chrono::minutes offset_local{}; auto offptr = offset ? offset : &offset_local; fields fds{}; fds.has_tod = true; - from_stream(is, fmt, fds, abbrev, offptr); + date::from_stream(is, fmt, fds, abbrev, offptr); if (!fds.ymd.ok() || !fds.tod.in_conventional_range()) is.setstate(std::ios::failbit); if (!is.fail()) - tp = round(sys_days(fds.ymd) - *offptr + fds.tod.to_duration()); + tp = round_i(sys_days(fds.ymd) - *offptr + fds.tod.to_duration()); return is; } @@ -7769,13 +8047,14 @@ from_stream(std::basic_istream& is, const CharT* fmt, std::chrono::minutes* offset = nullptr) { using CT = typename std::common_type::type; + using detail::round_i; fields fds{}; fds.has_tod = true; - from_stream(is, fmt, fds, abbrev, offset); + date::from_stream(is, fmt, fds, abbrev, offset); if (!fds.ymd.ok() || !fds.tod.in_conventional_range()) is.setstate(std::ios::failbit); if (!is.fail()) - tp = round(local_seconds{local_days(fds.ymd)} + fds.tod.to_duration()); + tp = round_i(local_seconds{local_days(fds.ymd)} + fds.tod.to_duration()); return is; } @@ -7788,12 +8067,13 @@ from_stream(std::basic_istream& is, const CharT* fmt, { using Duration = std::chrono::duration; using CT = typename std::common_type::type; + using detail::round_i; fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); + date::from_stream(is, fmt, fds, abbrev, offset); if (!fds.has_tod) is.setstate(std::ios::failbit); if (!is.fail()) - d = std::chrono::duration_cast(fds.tod.to_duration()); + d = round_i(fds.tod.to_duration()); return is; } @@ -7816,6 +8096,25 @@ struct parse_manip , offset_(offset) {} +#if HAS_STRING_VIEW + parse_manip(const CharT* format, Parsable& tp, + std::basic_string* abbrev = nullptr, + std::chrono::minutes* offset = nullptr) + : format_(format) + , tp_(tp) + , abbrev_(abbrev) + , offset_(offset) + {} + + parse_manip(std::basic_string_view format, Parsable& tp, + std::basic_string* abbrev = nullptr, + std::chrono::minutes* offset = nullptr) + : format_(format) + , tp_(tp) + , abbrev_(abbrev) + , offset_(offset) + {} +#endif // HAS_STRING_VIEW }; template @@ -7823,14 +8122,14 @@ std::basic_istream& operator>>(std::basic_istream& is, const parse_manip& x) { - return from_stream(is, x.format_.c_str(), x.tp_, x.abbrev_, x.offset_); + return date::from_stream(is, x.format_.c_str(), x.tp_, x.abbrev_, x.offset_); } template inline auto parse(const std::basic_string& format, Parsable& tp) - -> decltype(from_stream(std::declval&>(), + -> decltype(date::from_stream(std::declval&>(), format.c_str(), tp), parse_manip{format, tp}) { @@ -7842,7 +8141,7 @@ inline auto parse(const std::basic_string& format, Parsable& tp, std::basic_string& abbrev) - -> decltype(from_stream(std::declval&>(), + -> decltype(date::from_stream(std::declval&>(), format.c_str(), tp, &abbrev), parse_manip{format, tp, &abbrev}) { @@ -7854,7 +8153,7 @@ inline auto parse(const std::basic_string& format, Parsable& tp, std::chrono::minutes& offset) - -> decltype(from_stream(std::declval&>(), + -> decltype(date::from_stream(std::declval&>(), format.c_str(), tp, std::declval*>(), &offset), @@ -7868,7 +8167,7 @@ inline auto parse(const std::basic_string& format, Parsable& tp, std::basic_string& abbrev, std::chrono::minutes& offset) - -> decltype(from_stream(std::declval&>(), + -> decltype(date::from_stream(std::declval&>(), format.c_str(), tp, &abbrev, &offset), parse_manip{format, tp, &abbrev, &offset}) { @@ -7881,7 +8180,7 @@ template inline auto parse(const CharT* format, Parsable& tp) - -> decltype(from_stream(std::declval&>(), format, tp), + -> decltype(date::from_stream(std::declval&>(), format, tp), parse_manip{format, tp}) { return {format, tp}; @@ -7891,7 +8190,7 @@ template inline auto parse(const CharT* format, Parsable& tp, std::basic_string& abbrev) - -> decltype(from_stream(std::declval&>(), format, + -> decltype(date::from_stream(std::declval&>(), format, tp, &abbrev), parse_manip{format, tp, &abbrev}) { @@ -7902,7 +8201,7 @@ template inline auto parse(const CharT* format, Parsable& tp, std::chrono::minutes& offset) - -> decltype(from_stream(std::declval&>(), format, + -> decltype(date::from_stream(std::declval&>(), format, tp, std::declval*>(), &offset), parse_manip{format, tp, nullptr, &offset}) { @@ -7914,7 +8213,7 @@ inline auto parse(const CharT* format, Parsable& tp, std::basic_string& abbrev, std::chrono::minutes& offset) - -> decltype(from_stream(std::declval&>(), format, + -> decltype(date::from_stream(std::declval&>(), format, tp, &abbrev, &offset), parse_manip{format, tp, &abbrev, &offset}) {