From 328cecaa567e8b9da5dfcbcb4de9a550496bb55b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Kami=C5=84ski?= Date: Sun, 6 May 2018 19:13:36 +0200 Subject: [PATCH] Fixed addition of multi-year duration to year_month. * Added new overloads for operator+/- between year_month and duration that is convertible to years, so it is better candidate for operands that are convertible to both years and months. To preserve functionality, this operator is conditionally noexcept. * Reworked year_month_day, year_month_day_last, year_month_weekday, and year_month_weekday_last. * Added tests for this new functionality. --- include/date/date.h | 822 ++++++++---------- test/clock_cast_test/custom_clock.pass.cpp | 14 +- .../to_sys_return_utc_time.fail.cpp | 2 +- .../multi_year_duration_addition.pass.cpp | 297 +++++++ 4 files changed, 691 insertions(+), 444 deletions(-) create mode 100644 test/date_test/multi_year_duration_addition.pass.cpp diff --git a/include/date/date.h b/include/date/date.h index d2b7bf7..4eb1c3d 100644 --- a/include/date/date.h +++ b/include/date/date.h @@ -7,6 +7,7 @@ // Copyright (c) 2016 Adrian Colomitchi // Copyright (c) 2017 Florian Dang // Copyright (c) 2017 Paul Thompson +// Copyright (c) 2018 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 @@ -95,12 +96,14 @@ namespace date # define CONSTCD11 # define CONSTCD14 # define NOEXCEPT _NOEXCEPT +# define NOEXCEPT_COND(...) # else // VS2017 and later # define CONSTDATA constexpr const # define CONSTCD11 constexpr # define CONSTCD14 constexpr # define NOEXCEPT noexcept +# define NOEXCEPT_COND(...) noexcept(__VA_ARGS__) # endif #elif defined(__SUNPRO_CC) && __SUNPRO_CC <= 0x5150 @@ -109,6 +112,7 @@ namespace date # define CONSTCD11 constexpr # define CONSTCD14 # define NOEXCEPT noexcept +# define NOEXCEPT_COND(...) noexcept(__VA_ARGS__) #elif __cplusplus >= 201402 // C++14 @@ -116,12 +120,14 @@ namespace date # define CONSTCD11 constexpr # define CONSTCD14 constexpr # define NOEXCEPT noexcept +# define NOEXCEPT_COND(...) noexcept(__VA_ARGS__) #else // C++11 # define CONSTDATA constexpr const # define CONSTCD11 constexpr # define CONSTCD14 # define NOEXCEPT noexcept +# define NOEXCEPT_COND(...) noexcept(__VA_ARGS__) #endif #ifndef HAS_VOID_T @@ -490,6 +496,11 @@ template std::basic_ostream& operator<<(std::basic_ostream& os, const weekday_last& wdl); +#define NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS \ + NOEXCEPT_COND(std::is_nothrow_constructible::value \ + || (!std::is_convertible::value \ + && std::is_nothrow_constructible::value)) + // year_month class year_month @@ -504,10 +515,19 @@ public: CONSTCD11 date::year year() const NOEXCEPT; CONSTCD11 date::month month() const NOEXCEPT; - CONSTCD14 year_month& operator+=(const months& dm) NOEXCEPT; - CONSTCD14 year_month& operator-=(const months& dm) NOEXCEPT; - CONSTCD14 year_month& operator+=(const years& dy) NOEXCEPT; - CONSTCD14 year_month& operator-=(const years& dy) NOEXCEPT; + template ::value + >::type> + CONSTCD14 year_month& operator+=(const Duration& d) + NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS; + + template ::value + >::type> + CONSTCD14 year_month& operator-=(const Duration& d) + NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS; CONSTCD11 bool ok() const NOEXCEPT; }; @@ -524,9 +544,27 @@ CONSTCD14 year_month operator+(const months& dm, const year_month& ym) NOEXCEPT; 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 ::value + >::type> +CONSTCD11 year_month operator+(const year_month& ym, const Duration& d) +NOEXCEPT_COND(std::is_nothrow_constructible::value); + +template ::value + >::type> +CONSTCD11 year_month operator+(const Duration& d, const year_month& ym) +NOEXCEPT_COND(std::is_nothrow_constructible::value); + +template ::value + >::type> +CONSTCD11 year_month operator-(const year_month& ym, const Duration& d) +NOEXCEPT_COND(std::is_nothrow_constructible::value); template std::basic_ostream& @@ -650,10 +688,19 @@ public: CONSTCD14 year_month_day(sys_days dp) NOEXCEPT; CONSTCD14 explicit year_month_day(local_days dp) NOEXCEPT; - CONSTCD14 year_month_day& operator+=(const months& m) NOEXCEPT; - 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; + template ::value + >::type> + CONSTCD14 year_month_day& operator+=(const Duration& d) + NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS; + + template ::value + >::type> + CONSTCD14 year_month_day& operator-=(const Duration& d) + NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS; CONSTCD11 date::year year() const NOEXCEPT; CONSTCD11 date::month month() const NOEXCEPT; @@ -675,12 +722,29 @@ CONSTCD11 bool operator> (const year_month_day& x, const year_month_day& y) NOEX 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; -CONSTCD14 year_month_day operator+(const year_month_day& ymd, const months& dm) NOEXCEPT; -CONSTCD14 year_month_day operator+(const months& dm, const year_month_day& ymd) NOEXCEPT; -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; + +CONSTCD11 year_month operator/(const year& y, const month& m) NOEXCEPT; + +template ::value + >::type> +CONSTCD11 year_month_day operator+(const year_month_day& ymd, const Duration& d) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS; + +template ::value + >::type> +CONSTCD11 year_month_day operator+(const Duration& d, const year_month_day& ymd) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS; + +template ::value + >::type> +CONSTCD11 year_month_day operator-(const year_month_day& ymd, const Duration& d) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS; template std::basic_ostream& @@ -697,10 +761,19 @@ public: CONSTCD11 year_month_day_last(const date::year& y, const date::month_day_last& mdl) NOEXCEPT; - CONSTCD14 year_month_day_last& operator+=(const months& m) NOEXCEPT; - 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; + template ::value + >::type> + CONSTCD14 year_month_day_last& operator+=(const Duration& d) + NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS; + + template ::value + >::type> + CONSTCD14 year_month_day_last& operator-=(const Duration& d) + NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS; CONSTCD11 date::year year() const NOEXCEPT; CONSTCD11 date::month month() const NOEXCEPT; @@ -725,29 +798,29 @@ CONSTCD11 CONSTCD11 bool operator>=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD14 -year_month_day_last -operator+(const year_month_day_last& ymdl, const months& dm) NOEXCEPT; - -CONSTCD14 -year_month_day_last -operator+(const months& dm, const year_month_day_last& ymdl) NOEXCEPT; - +template ::value + >::type> CONSTCD11 -year_month_day_last -operator+(const year_month_day_last& ymdl, const years& dy) NOEXCEPT; + year_month_day_last operator+(const year_month_day_last& ymd, const Duration& d) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS; +template ::value + >::type> CONSTCD11 -year_month_day_last -operator+(const years& dy, const year_month_day_last& ymdl) NOEXCEPT; - -CONSTCD14 -year_month_day_last -operator-(const year_month_day_last& ymdl, const months& dm) NOEXCEPT; + year_month_day_last operator+(const Duration& d, const year_month_day_last& ymd) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS; +template ::value + >::type> CONSTCD11 -year_month_day_last -operator-(const year_month_day_last& ymdl, const years& dy) NOEXCEPT; + year_month_day_last operator-(const year_month_day_last& ymd, const Duration& d) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS; template std::basic_ostream& @@ -768,10 +841,19 @@ public: CONSTCD14 year_month_weekday(const sys_days& dp) NOEXCEPT; CONSTCD14 explicit year_month_weekday(const local_days& dp) NOEXCEPT; - CONSTCD14 year_month_weekday& operator+=(const months& m) NOEXCEPT; - 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; + template ::value + >::type> + CONSTCD14 year_month_weekday& operator+=(const Duration& d) + NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS; + + template ::value + >::type> + CONSTCD14 year_month_weekday& operator-=(const Duration& d) + NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS; CONSTCD11 date::year year() const NOEXCEPT; CONSTCD11 date::month month() const NOEXCEPT; @@ -793,29 +875,26 @@ CONSTCD11 CONSTCD11 bool operator!=(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT; -CONSTCD14 -year_month_weekday -operator+(const year_month_weekday& ymwd, const months& dm) NOEXCEPT; +template ::value + >::type> +CONSTCD11 year_month_weekday operator+(const year_month_weekday& ymd, const Duration& d) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS; -CONSTCD14 -year_month_weekday -operator+(const months& dm, const year_month_weekday& ymwd) NOEXCEPT; +template ::value + >::type> +CONSTCD11 year_month_weekday operator+(const Duration& d, const year_month_weekday& ymd) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS; -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; - -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 ::value + >::type> +CONSTCD11 year_month_weekday operator-(const year_month_weekday& ymd, const Duration& d) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS; template std::basic_ostream& @@ -833,10 +912,19 @@ public: CONSTCD11 year_month_weekday_last(const date::year& y, const date::month& m, const date::weekday_last& wdl) NOEXCEPT; - CONSTCD14 year_month_weekday_last& operator+=(const months& m) NOEXCEPT; - 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; + template ::value + >::type> + CONSTCD14 year_month_weekday_last& operator+=(const Duration& d) + NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS; + + template ::value + >::type> + CONSTCD14 year_month_weekday_last& operator-=(const Duration& d) + NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS; CONSTCD11 date::year year() const NOEXCEPT; CONSTCD11 date::month month() const NOEXCEPT; @@ -859,29 +947,29 @@ CONSTCD11 bool operator!=(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT; -CONSTCD14 -year_month_weekday_last -operator+(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT; - -CONSTCD14 -year_month_weekday_last -operator+(const months& dm, const year_month_weekday_last& ymwdl) NOEXCEPT; - +template ::value + >::type> CONSTCD11 -year_month_weekday_last -operator+(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT; + year_month_weekday_last operator+(const year_month_weekday_last& ymd, const Duration& d) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS; +template ::value + >::type> CONSTCD11 -year_month_weekday_last -operator+(const years& dy, const year_month_weekday_last& ymwdl) NOEXCEPT; - -CONSTCD14 -year_month_weekday_last -operator-(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT; + year_month_weekday_last operator+(const Duration& d, const year_month_weekday_last& ymd) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS; +template ::value + >::type> CONSTCD11 -year_month_weekday_last -operator-(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT; + year_month_weekday_last operator-(const year_month_weekday_last& ymd, const Duration& d) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS; template std::basic_ostream& @@ -1982,39 +2070,25 @@ CONSTCD11 inline year year_month::year() const NOEXCEPT {return y_;} CONSTCD11 inline month year_month::month() const NOEXCEPT {return m_;} CONSTCD11 inline bool year_month::ok() const NOEXCEPT {return y_.ok() && m_.ok();} +template CONSTCD14 inline year_month& -year_month::operator+=(const months& dm) NOEXCEPT +year_month::operator+=(const Duration& d) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS { - *this = *this + dm; + *this = *this + d; return *this; } +template CONSTCD14 inline year_month& -year_month::operator-=(const months& dm) NOEXCEPT +year_month::operator-=(const Duration& d) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS { - *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; + *this = *this - d; return *this; } @@ -2104,28 +2178,34 @@ operator-(const year_month& x, const year_month& y) NOEXCEPT months(static_cast(x.month()) - static_cast(y.month())); } +template CONSTCD11 inline year_month -operator+(const year_month& ym, const years& dy) NOEXCEPT +operator+(const year_month& ym, const Duration& d) +NOEXCEPT_COND(std::is_nothrow_constructible::value) { - return (ym.year() + dy) / ym.month(); + return (ym.year() + years(d)) / ym.month();; } +template CONSTCD11 inline year_month -operator+(const years& dy, const year_month& ym) NOEXCEPT +operator+(const Duration& d, const year_month& ym) +NOEXCEPT_COND(std::is_nothrow_constructible::value) { - return ym + dy; + return ym + years(d); } +template CONSTCD11 inline year_month -operator-(const year_month& ym, const years& dy) NOEXCEPT +operator-(const year_month& ym, const Duration& d) +NOEXCEPT_COND(std::is_nothrow_constructible::value) { - return ym + -dy; + return ym + -years(d); } template @@ -2397,42 +2477,6 @@ year_month_day_last::year_month_day_last(const date::year& y, , mdl_(mdl) {} -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 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();} @@ -2460,6 +2504,28 @@ year_month_day_last::day() const NOEXCEPT d[static_cast(month()) - 1] : date::day{29}; } +template +CONSTCD14 +inline +year_month_day_last& +year_month_day_last::operator+=(const Duration& d) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS +{ + *this = *this + d; + return *this; +} + +template +CONSTCD14 +inline +year_month_day_last& +year_month_day_last::operator-=(const Duration& d) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS +{ + *this = *this - d; + return *this; +} + CONSTCD14 inline year_month_day_last::operator sys_days() const NOEXCEPT @@ -2532,6 +2598,36 @@ operator>=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT return !(x < y); } +template +CONSTCD11 +inline +year_month_day_last +operator+(const year_month_day_last& ymd, const Duration& d) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS +{ + return (ymd.year() / ymd.month() + d) / last_spec(); +} + +template +CONSTCD11 +inline +year_month_day_last +operator+(const Duration& d, const year_month_day_last& ymd) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS +{ + return (ymd.year() / ymd.month() + d) / last_spec(); +} + +template +CONSTCD11 +inline +year_month_day_last +operator-(const year_month_day_last& ymd, const Duration& d) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS +{ + return (ymd.year() / ymd.month() - d) / last_spec(); +} + template inline std::basic_ostream& @@ -2540,54 +2636,6 @@ operator<<(std::basic_ostream& os, const year_month_day_last& ymd return os << ymdl.year() << '/' << ymdl.month_day_last(); } -CONSTCD14 -inline -year_month_day_last -operator+(const year_month_day_last& ymdl, const months& dm) NOEXCEPT -{ - return (ymdl.year() / ymdl.month() + dm) / last; -} - -CONSTCD14 -inline -year_month_day_last -operator+(const months& dm, const year_month_day_last& ymdl) NOEXCEPT -{ - return ymdl + dm; -} - -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 @@ -2623,39 +2671,25 @@ CONSTCD11 inline year year_month_day::year() const NOEXCEPT {return y_;} CONSTCD11 inline month year_month_day::month() const NOEXCEPT {return m_;} CONSTCD11 inline day year_month_day::day() const NOEXCEPT {return d_;} +template CONSTCD14 inline year_month_day& -year_month_day::operator+=(const months& m) NOEXCEPT +year_month_day::operator+=(const Duration& d) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS { - *this = *this + m; + *this = *this + d; return *this; } +template CONSTCD14 inline year_month_day& -year_month_day::operator-=(const months& m) NOEXCEPT +year_month_day::operator-=(const Duration& d) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS { - *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; + *this = *this - d; return *this; } @@ -2754,6 +2788,36 @@ operator>=(const year_month_day& x, const year_month_day& y) NOEXCEPT return !(x < y); } +template +CONSTCD11 +inline +year_month_day +operator+(const year_month_day& ymd, const Duration& d) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS +{ + return (ymd.year() / ymd.month() + d) / ymd.day(); +} + +template +CONSTCD11 +inline +year_month_day +operator+(const Duration& d, const year_month_day& ymd) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS +{ + return (ymd.year() / ymd.month() + d) / ymd.day(); +} + +template +CONSTCD11 +inline +year_month_day +operator-(const year_month_day& ymd, const Duration& d) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS +{ + return (ymd.year() / ymd.month() - d) / ymd.day(); +} + template inline std::basic_ostream& @@ -2792,54 +2856,6 @@ year_month_day::from_days(days dp) NOEXCEPT return year_month_day{date::year{y + (m <= 2)}, date::month(m), date::day(d)}; } -CONSTCD14 -inline -year_month_day -operator+(const year_month_day& ymd, const months& dm) NOEXCEPT -{ - return (ymd.year() / ymd.month() + dm) / ymd.day(); -} - -CONSTCD14 -inline -year_month_day -operator+(const months& dm, const year_month_day& ymd) NOEXCEPT -{ - return ymd + dm; -} - -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 @@ -2864,42 +2880,6 @@ year_month_weekday::year_month_weekday(const local_days& dp) NOEXCEPT : year_month_weekday(from_days(dp.time_since_epoch())) {} -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 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_;} @@ -2927,6 +2907,26 @@ year_month_weekday::weekday_indexed() const NOEXCEPT return wdi_; } +template +CONSTCD14 +year_month_weekday& +year_month_weekday::operator+=(const Duration& d) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS +{ + *this = *this + d; + return *this; +} + +template +CONSTCD14 +year_month_weekday& +year_month_weekday::operator-=(const Duration& d) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS +{ + *this = *this - d; + return *this; +} + CONSTCD14 inline year_month_weekday::operator sys_days() const NOEXCEPT @@ -2992,6 +2992,36 @@ operator!=(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT return !(x == y); } +template +CONSTCD11 +inline +year_month_weekday +operator+(const year_month_weekday& ymd, const Duration& d) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS +{ + return (ymd.year() / ymd.month() + d) / ymd.weekday_indexed(); +} + +template +CONSTCD11 +inline +year_month_weekday +operator+(const Duration& d, const year_month_weekday& ymd) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS +{ + return (ymd.year() / ymd.month() + d) / ymd.weekday_indexed();; +} + +template +CONSTCD11 +inline +year_month_weekday +operator-(const year_month_weekday& ymd, const Duration& d) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS +{ + return (ymd.year() / ymd.month() - d) / ymd.weekday_indexed(); +} + template inline std::basic_ostream& @@ -3001,54 +3031,6 @@ operator<<(std::basic_ostream& os, const year_month_weekday& ymwd << '/' << ymwdi.weekday_indexed(); } -CONSTCD14 -inline -year_month_weekday -operator+(const year_month_weekday& ymwd, const months& dm) NOEXCEPT -{ - return (ymwd.year() / ymwd.month() + dm) / ymwd.weekday_indexed(); -} - -CONSTCD14 -inline -year_month_weekday -operator+(const months& dm, const year_month_weekday& ymwd) NOEXCEPT -{ - return ymwd + dm; -} - -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 @@ -3061,42 +3043,6 @@ year_month_weekday_last::year_month_weekday_last(const date::year& y, , wdl_(wdl) {} -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 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_;} @@ -3116,6 +3062,28 @@ year_month_weekday_last::weekday_last() const NOEXCEPT return wdl_; } +template +CONSTCD14 +inline +year_month_weekday_last& +year_month_weekday_last::operator+=(const Duration& d) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS +{ + *this = *this + d; + return *this; +} + +template +CONSTCD14 +inline +year_month_weekday_last& +year_month_weekday_last::operator-=(const Duration& d) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS +{ + *this = *this - d; + return *this; +} + CONSTCD14 inline year_month_weekday_last::operator sys_days() const NOEXCEPT @@ -3164,6 +3132,36 @@ operator!=(const year_month_weekday_last& x, const year_month_weekday_last& y) N return !(x == y); } +template +CONSTCD11 +inline +year_month_weekday_last +operator+(const year_month_weekday_last& ymd, const Duration& d) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS +{ + return (ymd.year() / ymd.month() + d) / ymd.weekday_last(); +} + +template +CONSTCD11 +inline +year_month_weekday_last +operator+(const Duration& d, const year_month_weekday_last& ymd) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS +{ + return (ymd.year() / ymd.month() + d) / ymd.weekday_last();; +} + +template +CONSTCD11 +inline +year_month_weekday_last +operator-(const year_month_weekday_last& ymd, const Duration& d) +NOEXCEPT_CONVERTIBLE_TO_YEARS_OR_MONTHS +{ + return (ymd.year() / ymd.month() - d) / ymd.weekday_last(); +} + template inline std::basic_ostream& @@ -3172,54 +3170,6 @@ operator<<(std::basic_ostream& os, const year_month_weekday_last& return os << ymwdl.year() << '/' << ymwdl.month() << '/' << ymwdl.weekday_last(); } -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(); -} - -CONSTCD14 -inline -year_month_weekday_last -operator+(const months& dm, const year_month_weekday_last& ymwdl) NOEXCEPT -{ - return ymwdl + dm; -} - -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 diff --git a/test/clock_cast_test/custom_clock.pass.cpp b/test/clock_cast_test/custom_clock.pass.cpp index d9c9d8b..8d3ccba 100644 --- a/test/clock_cast_test/custom_clock.pass.cpp +++ b/test/clock_cast_test/custom_clock.pass.cpp @@ -30,16 +30,16 @@ int conversions = 0; //to/from impl struct mil_clock { - using duration = std::common_type_t; + using duration = typename std::common_type::type; using rep = duration::rep; using period = duration::period; using time_point = std::chrono::time_point; - static constexpr date::sys_days epoch = date::year{2000}/date::month{0}/date::day{1}; + static constexpr date::sys_days epoch{date::days{1000}}; template static - std::chrono::time_point> + std::chrono::time_point::type> to_sys(std::chrono::time_point const& tp) { ++conversions; @@ -48,11 +48,11 @@ struct mil_clock template static - std::chrono::time_point> + std::chrono::time_point::type> from_sys(std::chrono::time_point const& tp) { ++conversions; - using res = std::chrono::time_point>; + using res = std::chrono::time_point::type>; return res(tp - epoch); } @@ -103,11 +103,11 @@ namespace date struct clock_time_conversion { template - std::chrono::time_point> + std::chrono::time_point::type> operator()(std::chrono::time_point const& tp) { ++conversions; - using res = std::chrono::time_point>; + using res = std::chrono::time_point::type>; return res(tp.time_since_epoch() - mil_clock::epoch.time_since_epoch()); } }; diff --git a/test/clock_cast_test/to_sys_return_utc_time.fail.cpp b/test/clock_cast_test/to_sys_return_utc_time.fail.cpp index d5364ce..6fc7a2b 100644 --- a/test/clock_cast_test/to_sys_return_utc_time.fail.cpp +++ b/test/clock_cast_test/to_sys_return_utc_time.fail.cpp @@ -34,7 +34,7 @@ struct bad_clock date::utc_time to_sys(std::chrono::time_point const& tp) { - return utc_time(tp.time_since_epoch()); + return date::utc_time(tp.time_since_epoch()); } }; diff --git a/test/date_test/multi_year_duration_addition.pass.cpp b/test/date_test/multi_year_duration_addition.pass.cpp new file mode 100644 index 0000000..0de3479 --- /dev/null +++ b/test/date_test/multi_year_duration_addition.pass.cpp @@ -0,0 +1,297 @@ +// The MIT License (MIT) +// +// Copyright (c) 2018 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. + +#include "date.h" +#include +#include +#include + +#define CPP11_ASSERT(...) static_assert(__VA_ARGS__, "") + +#if __cplusplus >= 201402 +// C++14 +# define CPP14_ASSERT(...) static_assert(__VA_ARGS__, "") +#else +// C++11 +# define CPP14_ASSERT(...) assert(__VA_ARGS__) +#endif + +#define NOEXCEPT_ASSERT(...) static_assert(noexcept(__VA_ARGS__), "") + +//Invocation involves a conversion between duration that is currently +//not marked as noexcept. +#define NOEXCEPT_CONVERSION(...) + +template +constexpr T copy(T const& t) noexcept { return t; } + + +int +main() +{ + using namespace date; + using namespace std::chrono; + + using decades = duration, years::period>>; + using decamonths = duration, months::period>>; + + constexpr months one_month{1}; + constexpr years one_year{1}; + constexpr decades one_decade{1}; + constexpr decamonths one_decamonth{1}; + + { + constexpr year_month ym = 2001_y/feb; + CPP14_ASSERT(ym + one_month == 2001_y/mar); + NOEXCEPT_ASSERT(ym + one_month); + CPP14_ASSERT(one_month + ym == 2001_y/mar); + NOEXCEPT_ASSERT(one_month + ym); + CPP14_ASSERT(ym - one_month == 2001_y/jan); + NOEXCEPT_ASSERT(ym - one_month); + CPP14_ASSERT((copy(ym) += one_month) == 2001_y/mar); + NOEXCEPT_ASSERT(copy(ym) += one_month); + CPP14_ASSERT((copy(ym) -= one_month) == 2001_y/jan); + NOEXCEPT_ASSERT(copy(ym) -= one_month); + + CPP11_ASSERT(ym + one_year == 2002_y/feb); + NOEXCEPT_ASSERT(ym + one_year); + CPP11_ASSERT(one_year + ym == 2002_y/feb); + NOEXCEPT_ASSERT(one_year + ym); + CPP11_ASSERT(ym - one_year == 2000_y/feb); + NOEXCEPT_ASSERT(ym - one_year); + CPP14_ASSERT((copy(ym) += one_year) == 2002_y/feb); + NOEXCEPT_ASSERT(copy(ym) += one_year); + CPP14_ASSERT((copy(ym) -= one_year) == 2000_y/feb); + NOEXCEPT_ASSERT(copy(ym) -= one_year); + + CPP11_ASSERT(ym + one_decade == 2011_y/feb); + NOEXCEPT_CONVERSION(ym + one_decade); + CPP11_ASSERT(one_decade + ym == 2011_y/feb); + NOEXCEPT_CONVERSION(one_decade + ym); + CPP11_ASSERT(ym - one_decade == 1991_y/feb); + NOEXCEPT_CONVERSION(ym - one_decade); + CPP14_ASSERT((copy(ym) += one_decade) == 2011_y/feb); + NOEXCEPT_CONVERSION(copy(ym) += one_decade); + CPP14_ASSERT((copy(ym) -= one_decade) == 1991_y/feb); + NOEXCEPT_CONVERSION(copy(ym) -= one_decade); + + CPP14_ASSERT(ym + one_decamonth == 2001_y/dec); + NOEXCEPT_CONVERSION(ym + one_decamonth); + CPP14_ASSERT(one_decamonth + ym == 2001_y/dec); + NOEXCEPT_CONVERSION(one_decamonth + ym); + CPP14_ASSERT(ym - one_decamonth == 2000_y/apr); + NOEXCEPT_CONVERSION(ym - one_decamonth); + CPP14_ASSERT((copy(ym) += one_decamonth) == 2001_y/dec); + NOEXCEPT_CONVERSION(copy(ym) += one_decamonth); + CPP14_ASSERT((copy(ym) -= one_decamonth) == 2000_y/apr); + NOEXCEPT_CONVERSION(copy(ym) -= one_decamonth); + } + + { + constexpr year_month_day ym = 2001_y/feb/10; + CPP14_ASSERT(ym + one_month == 2001_y/mar/10); + NOEXCEPT_ASSERT(ym + one_month); + CPP14_ASSERT(one_month + ym == 2001_y/mar/10); + NOEXCEPT_ASSERT(one_month + ym); + CPP14_ASSERT(ym - one_month == 2001_y/jan/10); + NOEXCEPT_ASSERT(ym - one_month); + CPP14_ASSERT((copy(ym) += one_month) == 2001_y/mar/10); + NOEXCEPT_ASSERT(copy(ym) += one_month); + CPP14_ASSERT((copy(ym) -= one_month) == 2001_y/jan/10); + NOEXCEPT_ASSERT(copy(ym) -= one_month); + + CPP11_ASSERT(ym + one_year == 2002_y/feb/10); + NOEXCEPT_ASSERT(ym + one_year); + CPP11_ASSERT(one_year + ym == 2002_y/feb/10); + NOEXCEPT_ASSERT(one_year + ym); + CPP11_ASSERT(ym - one_year == 2000_y/feb/10); + NOEXCEPT_ASSERT(ym - one_year); + CPP14_ASSERT((copy(ym) += one_year) == 2002_y/feb/10); + NOEXCEPT_ASSERT(copy(ym) += one_year); + CPP14_ASSERT((copy(ym) -= one_year) == 2000_y/feb/10); + NOEXCEPT_ASSERT(copy(ym) -= one_year); + + CPP11_ASSERT(ym + one_decade == 2011_y/feb/10); + NOEXCEPT_CONVERSION(ym + one_decade); + CPP11_ASSERT(one_decade + ym == 2011_y/feb/10); + NOEXCEPT_CONVERSION(one_decade + ym); + CPP11_ASSERT(ym - one_decade == 1991_y/feb/10); + NOEXCEPT_CONVERSION(ym - one_decade); + CPP14_ASSERT((copy(ym) += one_decade) == 2011_y/feb/10); + NOEXCEPT_CONVERSION(copy(ym) += one_decade); + CPP14_ASSERT((copy(ym) -= one_decade) == 1991_y/feb/10); + NOEXCEPT_CONVERSION(copy(ym) -= one_decade); + + CPP14_ASSERT(ym + one_decamonth == 2001_y/dec/10); + NOEXCEPT_CONVERSION(ym + one_decamonth); + CPP14_ASSERT(one_decamonth + ym == 2001_y/dec/10); + NOEXCEPT_CONVERSION(one_decamonth + ym); + CPP14_ASSERT(ym - one_decamonth == 2000_y/apr/10); + NOEXCEPT_CONVERSION(ym - one_decamonth); + CPP14_ASSERT((copy(ym) += one_decamonth) == 2001_y/dec/10); + NOEXCEPT_CONVERSION(copy(ym) += one_decamonth); + CPP14_ASSERT((copy(ym) -= one_decamonth) == 2000_y/apr/10); + NOEXCEPT_CONVERSION(copy(ym) -= one_decamonth); + } + + { + constexpr year_month_day_last ym = 2001_y/feb/last; + CPP14_ASSERT(ym + one_month == 2001_y/mar/last); + NOEXCEPT_ASSERT(ym + one_month); + CPP14_ASSERT(one_month + ym == 2001_y/mar/last); + NOEXCEPT_ASSERT(one_month + ym); + CPP14_ASSERT(ym - one_month == 2001_y/jan/last); + NOEXCEPT_ASSERT(ym - one_month); + CPP14_ASSERT((copy(ym) += one_month) == 2001_y/mar/last); + NOEXCEPT_ASSERT(copy(ym) += one_month); + CPP14_ASSERT((copy(ym) -= one_month) == 2001_y/jan/last); + NOEXCEPT_ASSERT(copy(ym) -= one_month); + + CPP11_ASSERT(ym + one_year == 2002_y/feb/last); + NOEXCEPT_ASSERT(ym + one_year); + CPP11_ASSERT(one_year + ym == 2002_y/feb/last); + NOEXCEPT_ASSERT(one_year + ym); + CPP11_ASSERT(ym - one_year == 2000_y/feb/last); + NOEXCEPT_ASSERT(ym - one_year); + CPP14_ASSERT((copy(ym) += one_year) == 2002_y/feb/last); + NOEXCEPT_ASSERT(copy(ym) += one_year); + CPP14_ASSERT((copy(ym) -= one_year) == 2000_y/feb/last); + NOEXCEPT_ASSERT(copy(ym) -= one_year); + + CPP11_ASSERT(ym + one_decade == 2011_y/feb/last); + NOEXCEPT_CONVERSION(ym + one_decade); + CPP11_ASSERT(one_decade + ym == 2011_y/feb/last); + NOEXCEPT_CONVERSION(one_decade + ym); + CPP11_ASSERT(ym - one_decade == 1991_y/feb/last); + NOEXCEPT_CONVERSION(ym - one_decade); + CPP14_ASSERT((copy(ym) += one_decade) == 2011_y/feb/last); + NOEXCEPT_CONVERSION(copy(ym) += one_decade); + CPP14_ASSERT((copy(ym) -= one_decade) == 1991_y/feb/last); + NOEXCEPT_CONVERSION(copy(ym) -= one_decade); + + CPP14_ASSERT(ym + one_decamonth == 2001_y/dec/last); + NOEXCEPT_CONVERSION(ym + one_decamonth); + CPP14_ASSERT(one_decamonth + ym == 2001_y/dec/last); + NOEXCEPT_CONVERSION(one_decamonth + ym); + CPP14_ASSERT(ym - one_decamonth == 2000_y/apr/last); + NOEXCEPT_CONVERSION(ym - one_decamonth); + CPP14_ASSERT((copy(ym) += one_decamonth) == 2001_y/dec/last); + NOEXCEPT_CONVERSION(copy(ym) += one_decamonth); + CPP14_ASSERT((copy(ym) -= one_decamonth) == 2000_y/apr/last); + NOEXCEPT_CONVERSION(copy(ym) -= one_decamonth); + } + + { + constexpr year_month_weekday ym = 2001_y/feb/fri[4]; + CPP14_ASSERT(ym + one_month == 2001_y/mar/fri[4]); + NOEXCEPT_ASSERT(ym + one_month); + CPP14_ASSERT(one_month + ym == 2001_y/mar/fri[4]); + NOEXCEPT_ASSERT(one_month + ym); + CPP14_ASSERT(ym - one_month == 2001_y/jan/fri[4]); + NOEXCEPT_ASSERT(ym - one_month); + CPP14_ASSERT((copy(ym) += one_month) == 2001_y/mar/fri[4]); + NOEXCEPT_ASSERT(copy(ym) += one_month); + CPP14_ASSERT((copy(ym) -= one_month) == 2001_y/jan/fri[4]); + NOEXCEPT_ASSERT(copy(ym) -= one_month); + + CPP11_ASSERT(ym + one_year == 2002_y/feb/fri[4]); + NOEXCEPT_ASSERT(ym + one_year); + CPP11_ASSERT(one_year + ym == 2002_y/feb/fri[4]); + NOEXCEPT_ASSERT(one_year + ym); + CPP11_ASSERT(ym - one_year == 2000_y/feb/fri[4]); + NOEXCEPT_ASSERT(ym - one_year); + CPP14_ASSERT((copy(ym) += one_year) == 2002_y/feb/fri[4]); + NOEXCEPT_ASSERT(copy(ym) += one_year); + CPP14_ASSERT((copy(ym) -= one_year) == 2000_y/feb/fri[4]); + NOEXCEPT_ASSERT(copy(ym) -= one_year); + + CPP11_ASSERT(ym + one_decade == 2011_y/feb/fri[4]); + NOEXCEPT_CONVERSION(ym + one_decade); + CPP11_ASSERT(one_decade + ym == 2011_y/feb/fri[4]); + NOEXCEPT_CONVERSION(one_decade + ym); + CPP11_ASSERT(ym - one_decade == 1991_y/feb/fri[4]); + NOEXCEPT_CONVERSION(ym - one_decade); + CPP14_ASSERT((copy(ym) += one_decade) == 2011_y/feb/fri[4]); + NOEXCEPT_CONVERSION(copy(ym) += one_decade); + CPP14_ASSERT((copy(ym) -= one_decade) == 1991_y/feb/fri[4]); + NOEXCEPT_CONVERSION(copy(ym) -= one_decade); + + CPP14_ASSERT(ym + one_decamonth == 2001_y/dec/fri[4]); + NOEXCEPT_CONVERSION(ym + one_decamonth); + CPP14_ASSERT(one_decamonth + ym == 2001_y/dec/fri[4]); + NOEXCEPT_CONVERSION(one_decamonth + ym); + CPP14_ASSERT(ym - one_decamonth == 2000_y/apr/fri[4]); + NOEXCEPT_CONVERSION(ym - one_decamonth); + CPP14_ASSERT((copy(ym) += one_decamonth) == 2001_y/dec/fri[4]); + NOEXCEPT_CONVERSION(copy(ym) += one_decamonth); + CPP14_ASSERT((copy(ym) -= one_decamonth) == 2000_y/apr/fri[4]); + NOEXCEPT_CONVERSION(copy(ym) -= one_decamonth); + } + + { + constexpr year_month_weekday_last ym = 2001_y/feb/fri[last]; + CPP14_ASSERT(ym + one_month == 2001_y/mar/fri[last]); + NOEXCEPT_ASSERT(ym + one_month); + CPP14_ASSERT(one_month + ym == 2001_y/mar/fri[last]); + NOEXCEPT_ASSERT(one_month + ym); + CPP14_ASSERT(ym - one_month == 2001_y/jan/fri[last]); + NOEXCEPT_ASSERT(ym - one_month); + CPP14_ASSERT((copy(ym) += one_month) == 2001_y/mar/fri[last]); + NOEXCEPT_ASSERT(copy(ym) += one_month); + CPP14_ASSERT((copy(ym) -= one_month) == 2001_y/jan/fri[last]); + NOEXCEPT_ASSERT(copy(ym) -= one_month); + + CPP11_ASSERT(ym + one_year == 2002_y/feb/fri[last]); + NOEXCEPT_ASSERT(ym + one_year); + CPP11_ASSERT(one_year + ym == 2002_y/feb/fri[last]); + NOEXCEPT_ASSERT(one_year + ym); + CPP11_ASSERT(ym - one_year == 2000_y/feb/fri[last]); + NOEXCEPT_ASSERT(ym - one_year); + CPP14_ASSERT((copy(ym) += one_year) == 2002_y/feb/fri[last]); + NOEXCEPT_ASSERT(copy(ym) += one_year); + CPP14_ASSERT((copy(ym) -= one_year) == 2000_y/feb/fri[last]); + NOEXCEPT_ASSERT(copy(ym) -= one_year); + + CPP11_ASSERT(ym + one_decade == 2011_y/feb/fri[last]); + NOEXCEPT_CONVERSION(ym + one_decade); + CPP11_ASSERT(one_decade + ym == 2011_y/feb/fri[last]); + NOEXCEPT_CONVERSION(one_decade + ym); + CPP11_ASSERT(ym - one_decade == 1991_y/feb/fri[last]); + NOEXCEPT_CONVERSION(ym - one_decade); + CPP14_ASSERT((copy(ym) += one_decade) == 2011_y/feb/fri[last]); + NOEXCEPT_CONVERSION(copy(ym) += one_decade); + CPP14_ASSERT((copy(ym) -= one_decade) == 1991_y/feb/fri[last]); + NOEXCEPT_CONVERSION(copy(ym) -= one_decade); + + CPP14_ASSERT(ym + one_decamonth == 2001_y/dec/fri[last]); + NOEXCEPT_CONVERSION(ym + one_decamonth); + CPP14_ASSERT(one_decamonth + ym == 2001_y/dec/fri[last]); + NOEXCEPT_CONVERSION(one_decamonth + ym); + CPP14_ASSERT(ym - one_decamonth == 2000_y/apr/fri[last]); + NOEXCEPT_CONVERSION(ym - one_decamonth); + CPP14_ASSERT((copy(ym) += one_decamonth) == 2001_y/dec/fri[last]); + NOEXCEPT_CONVERSION(copy(ym) += one_decamonth); + CPP14_ASSERT((copy(ym) -= one_decamonth) == 2000_y/apr/fri[last]); + NOEXCEPT_CONVERSION(copy(ym) -= one_decamonth); + } + +}