Index: include/chrono =================================================================== --- include/chrono +++ include/chrono @@ -1592,6 +1592,19 @@ template using file_time = time_point; + +template +using sys_time = time_point; +using sys_seconds = sys_time; +using sys_days = sys_time; + +struct local_t {}; +template +using local_time = time_point; +using local_seconds = local_time; +using local_days = local_time; + + struct _LIBCPP_TYPE_VIS last_spec { explicit last_spec() = default; }; class _LIBCPP_TYPE_VIS day { @@ -1812,9 +1825,12 @@ unsigned char __wd; public: weekday() = default; - explicit inline constexpr weekday(unsigned __val) noexcept: __wd(static_cast(__val)) {} -// inline constexpr weekday(const sys_days& dp) noexcept; -// explicit constexpr weekday(const local_days& dp) noexcept; + inline explicit constexpr weekday(unsigned __val) noexcept : __wd(static_cast(__val)) {} + inline constexpr weekday(const sys_days& __sysd) noexcept + : __wd(__weekday_from_days(__sysd.time_since_epoch().count())) {} + inline explicit constexpr weekday(const local_days& __locd) noexcept + : __wd(__weekday_from_days(__locd.time_since_epoch().count())) {} + inline constexpr weekday& operator++() noexcept { __wd = (__wd == 6 ? 0 : __wd + 1); return *this; } inline constexpr weekday operator++(int) noexcept { weekday __tmp = *this; ++(*this); return __tmp; } inline constexpr weekday& operator--() noexcept { __wd = (__wd == 0 ? 6 : __wd - 1); return *this; } @@ -1821,13 +1837,25 @@ inline constexpr weekday operator--(int) noexcept { weekday __tmp = *this; --(*this); return __tmp; } constexpr weekday& operator+=(const days& __dd) noexcept; constexpr weekday& operator-=(const days& __dd) noexcept; - explicit inline constexpr operator unsigned() const noexcept { return __wd; } + inline explicit constexpr operator unsigned() const noexcept { return __wd; } inline constexpr bool ok() const noexcept { return __wd <= 6; } - constexpr weekday_indexed operator[](unsigned __index) const noexcept; - constexpr weekday_last operator[](last_spec) const noexcept; + constexpr weekday_indexed operator[](unsigned __index) const noexcept; + constexpr weekday_last operator[](last_spec) const noexcept; + + static constexpr unsigned char __weekday_from_days(int __days) noexcept; }; + +// https://howardhinnant.github.io/date_algorithms.html#weekday_from_days inline constexpr +unsigned char weekday::__weekday_from_days(int __days) noexcept +{ + return static_cast( + static_cast(__days >= -4 ? (__days+4) % 7 : (__days+5) % 7 + 6) + ); +} + +inline constexpr bool operator==(const weekday& __lhs, const weekday& __rhs) noexcept { return static_cast(__lhs) == static_cast(__rhs); } @@ -2221,6 +2249,7 @@ constexpr year_month operator-(const year_month& __lhs, const years& __rhs) noexcept { return __lhs + -__rhs; } +class year_month_day_last; class _LIBCPP_TYPE_VIS year_month_day { private: @@ -2232,25 +2261,67 @@ inline constexpr year_month_day( const chrono::year& __yval, const chrono::month& __mval, const chrono::day& __dval) noexcept : __y{__yval}, __m{__mval}, __d{__dval} {} -// inline constexpr year_month_day(const year_month_day_last& __ymdl) noexcept; -// inline constexpr year_month_day(const sys_days& dp) noexcept; -// inline explicit constexpr year_month_day(const local_days& dp) noexcept; + constexpr year_month_day(const year_month_day_last& __ymdl) noexcept; + inline constexpr year_month_day(const sys_days& __sysd) noexcept + : year_month_day(__from_days(__sysd.time_since_epoch())) {} + inline explicit constexpr year_month_day(const local_days& __locd) noexcept + : year_month_day(__from_days(__locd.time_since_epoch())) {} + constexpr year_month_day& operator+=(const months& __dm) noexcept; constexpr year_month_day& operator-=(const months& __dm) noexcept; constexpr year_month_day& operator+=(const years& __dy) noexcept; constexpr year_month_day& operator-=(const years& __dy) noexcept; - inline constexpr chrono::year year() const noexcept { return __y; } + + inline constexpr chrono::year year() const noexcept { return __y; } inline constexpr chrono::month month() const noexcept { return __m; } - inline constexpr chrono::day day() const noexcept { return __d; } -// inline constexpr operator sys_days() const noexcept; -// inline explicit constexpr operator local_days() const noexcept; + inline constexpr chrono::day day() const noexcept { return __d; } + inline constexpr operator sys_days() const noexcept { return sys_days{__to_days()}; } + inline explicit constexpr operator local_days() const noexcept { return local_days{__to_days()}; } -// TODO: This is not quite correct; requires the calendar bits to do right -// d_ is in the range [1d, (y_/m_/last).day()], - inline constexpr bool ok() const noexcept { return __y.ok() && __m.ok() && __d.ok(); } + constexpr bool ok() const noexcept; + + static constexpr year_month_day __from_days(days __d) noexcept; + constexpr days __to_days() const noexcept; }; + +// https://howardhinnant.github.io/date_algorithms.html#civil_from_days inline constexpr +year_month_day +year_month_day::__from_days(days __d) noexcept +{ + static_assert(std::numeric_limits::digits >= 18, ""); + static_assert(std::numeric_limits::digits >= 20 , ""); + const int __z = __d.count() + 719468; + const int __era = (__z >= 0 ? __z : __z - 146096) / 146097; + const unsigned __doe = static_cast(__z - __era * 146097); // [0, 146096] + const unsigned __yoe = (__doe - __doe/1460 + __doe/36524 - __doe/146096) / 365; // [0, 399] + const int __yr = static_cast(__yoe) + __era * 400; + const unsigned __doy = __doe - (365 * __yoe + __yoe/4 - __yoe/100); // [0, 365] + const unsigned __mp = (5 * __doy + 2)/153; // [0, 11] + const unsigned __dy = __doy - (153 * __mp + 2)/5 + 1; // [1, 31] + const unsigned __mth = __mp + (__mp < 10 ? 3 : -9); // [1, 12] + return year_month_day{chrono::year{__yr + (__mth <= 2)}, chrono::month{__mth}, chrono::day{__dy}}; +} + +// https://howardhinnant.github.io/date_algorithms.html#days_from_civil +inline constexpr days year_month_day::__to_days() const noexcept +{ + static_assert(std::numeric_limits::digits >= 18, ""); + static_assert(std::numeric_limits::digits >= 20 , ""); + + const int __yr = static_cast(__y) - (__m <= February); + const unsigned __mth = static_cast(__m); + const unsigned __dy = static_cast(__d); + + const int __era = (__yr >= 0 ? __yr : __yr - 399) / 400; + const unsigned __yoe = static_cast(__yr - __era * 400); // [0, 399] + const unsigned __doy = (153 * (__mth + (__mth > 2 ? -3 : 9)) + 2) / 5 + __dy-1; // [0, 365] + const unsigned __doe = __yoe * 365 + __yoe/4 - __yoe/100 + __doy; // [0, 146096] + return days{__era * 146097 + static_cast(__doe) - 719468}; +} + +inline constexpr bool operator==(const year_month_day& __lhs, const year_month_day& __rhs) noexcept { return __lhs.year() == __rhs.year() && __lhs.month() == __rhs.month() && __lhs.day() == __rhs.day(); } @@ -2347,16 +2418,30 @@ constexpr year_month_day_last& operator+=(const years& __y) noexcept; constexpr year_month_day_last& operator-=(const years& __y) noexcept; - constexpr chrono::year year() const noexcept { return __y; } - constexpr chrono::month month() const noexcept { return __mdl.month(); } - constexpr chrono::month_day_last month_day_last() const noexcept { return __mdl; } -// constexpr chrono::day day() const noexcept; -// constexpr operator sys_days() const noexcept; -// explicit constexpr operator local_days() const noexcept; - constexpr bool ok() const noexcept { return __y.ok() && __mdl.ok(); } + inline constexpr chrono::year year() const noexcept { return __y; } + inline constexpr chrono::month month() const noexcept { return __mdl.month(); } + inline constexpr chrono::month_day_last month_day_last() const noexcept { return __mdl; } + constexpr chrono::day day() const noexcept; + inline constexpr operator sys_days() const noexcept { return sys_days{year()/month()/day()}; } + inline explicit constexpr operator local_days() const noexcept { return local_days{year()/month()/day()}; } + inline constexpr bool ok() const noexcept { return __y.ok() && __mdl.ok(); } }; inline constexpr +chrono::day year_month_day_last::day() const noexcept +{ + constexpr chrono::day __d[] = + { + chrono::day(31), chrono::day(28), chrono::day(31), + chrono::day(30), chrono::day(31), chrono::day(30), + chrono::day(31), chrono::day(31), chrono::day(30), + chrono::day(31), chrono::day(30), chrono::day(31) + }; + return month() != February || !__y.is_leap() ? + __d[static_cast(month()) - 1] : chrono::day{29}; +} + +inline constexpr bool operator==(const year_month_day_last& __lhs, const year_month_day_last& __rhs) noexcept { return __lhs.year() == __rhs.year() && __lhs.month_day_last() == __rhs.month_day_last(); } @@ -2429,6 +2514,15 @@ inline constexpr year_month_day_last& year_month_day_last::operator+=(const years& __dy) noexcept { *this = *this + __dy; return *this; } inline constexpr year_month_day_last& year_month_day_last::operator-=(const years& __dy) noexcept { *this = *this - __dy; return *this; } +inline constexpr year_month_day::year_month_day(const year_month_day_last& __ymdl) noexcept + : __y{__ymdl.year()}, __m{__ymdl.month()}, __d{__ymdl.day()} {} + +inline constexpr bool year_month_day::ok() const noexcept +{ + if (!__y.ok() || !__m.ok()) return false; + return chrono::day{1} <= __d && __d <= (__y / __m / last).day(); +} + class _LIBCPP_TYPE_VIS year_month_weekday { chrono::year __y; chrono::month __m; @@ -2438,8 +2532,10 @@ constexpr year_month_weekday(const chrono::year& __yval, const chrono::month& __mval, const chrono::weekday_indexed& __wdival) noexcept : __y{__yval}, __m{__mval}, __wdi{__wdival} {} -// constexpr year_month_weekday(const sys_days& dp) noexcept; -// explicit constexpr year_month_weekday(const local_days& dp) noexcept; + constexpr year_month_weekday(const sys_days& __sysd) noexcept + : year_month_weekday(__from_days(__sysd.time_since_epoch())) {} + inline explicit constexpr year_month_weekday(const local_days& __locd) noexcept + : year_month_weekday(__from_days(__locd.time_since_epoch())) {} constexpr year_month_weekday& operator+=(const months& m) noexcept; constexpr year_month_weekday& operator-=(const months& m) noexcept; constexpr year_month_weekday& operator+=(const years& y) noexcept; @@ -2451,8 +2547,8 @@ inline constexpr unsigned index() const noexcept { return __wdi.index(); } inline constexpr chrono::weekday_indexed weekday_indexed() const noexcept { return __wdi; } -// constexpr operator sys_days() const noexcept; -// explicit constexpr operator local_days() const noexcept; + inline constexpr operator sys_days() const noexcept { return sys_days{__to_days()}; } + inline explicit constexpr operator local_days() const noexcept { return local_days{__to_days()}; } inline constexpr bool ok() const noexcept { if (!__y.ok() || !__m.ok() || !__wdi.ok()) return false; @@ -2459,9 +2555,30 @@ // TODO: make sure it's a valid date return true; } + + static constexpr year_month_weekday __from_days(days __d) noexcept; + constexpr days __to_days() const noexcept; }; inline constexpr +year_month_weekday year_month_weekday::__from_days(days __d) noexcept +{ + const sys_days __sysd{__d}; + const chrono::weekday __wd = chrono::weekday(__sysd); + const year_month_day __ymd = year_month_day(__sysd); + return year_month_weekday{__ymd.year(), __ymd.month(), + __wd[(static_cast(__ymd.day())-1)/7+1]}; +} + +inline constexpr +days year_month_weekday::__to_days() const noexcept +{ + const sys_days __sysd = sys_days(__y/__m/1); + return (__sysd + (__wdi.weekday() - chrono::weekday(__sysd) + days{(__wdi.index()-1)*7})) + .time_since_epoch(); +} + +inline constexpr bool operator==(const year_month_weekday& __lhs, const year_month_weekday& __rhs) noexcept { return __lhs.year() == __rhs.year() && __lhs.month() == __rhs.month() && __lhs.weekday_indexed() == __rhs.weekday_indexed(); } @@ -2538,12 +2655,23 @@ inline constexpr chrono::month month() const noexcept { return __m; } inline constexpr chrono::weekday weekday() const noexcept { return __wdl.weekday(); } inline constexpr chrono::weekday_last weekday_last() const noexcept { return __wdl; } -// constexpr operator sys_days() const noexcept; -// explicit constexpr operator local_days() const noexcept; + inline constexpr operator sys_days() const noexcept { return sys_days{__to_days()}; } + inline explicit constexpr operator local_days() const noexcept { return local_days{__to_days()}; } inline constexpr bool ok() const noexcept { return __y.ok() && __m.ok() && __wdl.ok(); } + + constexpr days __to_days() const noexcept; + }; inline constexpr +days year_month_weekday_last::__to_days() const noexcept +{ + const sys_days __last = sys_days{__y/__m/last}; + return (__last - (chrono::weekday{__last} - __wdl.weekday())).time_since_epoch(); + +} + +inline constexpr bool operator==(const year_month_weekday_last& __lhs, const year_month_weekday_last& __rhs) noexcept { return __lhs.year() == __rhs.year() && __lhs.month() == __rhs.month() && __lhs.weekday_last() == __rhs.weekday_last(); } Index: test/std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.members/ctor.local_days.pass.cpp =================================================================== --- test/std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.members/ctor.local_days.pass.cpp +++ test/std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.members/ctor.local_days.pass.cpp @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 + +// +// class weekday; + +// constexpr weekday(const local_days& dp) noexcept; +// +// Effects: Constructs an object of type weekday by computing what day +// of the week corresponds to the local_days dp, and representing +// that day of the week in wd_ +// +// Remarks: For any value ymd of type year_month_day for which ymd.ok() is true, +// ymd == year_month_day{sys_days{ymd}} is true. +// +// [Example: +// If dp represents 1970-01-01, the constructed weekday represents Thursday by storing 4 in wd_. +// —end example] + +#include +#include +#include + +#include "test_macros.h" + +int main() +{ + using local_days = std::chrono::local_days; + using days = std::chrono::days; + using weekday = std::chrono::weekday; + + ASSERT_NOEXCEPT(weekday{std::declval()}); + + { + constexpr local_days sd{}; // 1-Jan-1970 was a Thursday + constexpr weekday wd{sd}; + + static_assert( wd.ok(), ""); + static_assert(static_cast(wd) == 4, ""); + } + + { + constexpr local_days sd{days{10957+32}}; // 2-Feb-2000 was a Wednesday + constexpr weekday wd{sd}; + + static_assert( wd.ok(), ""); + static_assert(static_cast(wd) == 3, ""); + } + + + { + constexpr local_days sd{days{-10957}}; // 2-Jan-1940 was a Tuesday + constexpr weekday wd{sd}; + + static_assert( wd.ok(), ""); + static_assert(static_cast(wd) == 2, ""); + } + + { + local_days sd{days{-(10957+34)}}; // 29-Nov-1939 was a Wednesday + weekday wd{sd}; + + assert( wd.ok()); + assert(static_cast(wd) == 3); + } +} Index: test/std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.members/ctor.sys_days.pass.cpp =================================================================== --- test/std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.members/ctor.sys_days.pass.cpp +++ test/std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.members/ctor.sys_days.pass.cpp @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 + +// +// class weekday; + +// constexpr weekday(const sys_days& dp) noexcept; +// +// Effects: Constructs an object of type weekday by computing what day +// of the week corresponds to the sys_days dp, and representing +// that day of the week in wd_ +// +// Remarks: For any value ymd of type year_month_day for which ymd.ok() is true, +// ymd == year_month_day{sys_days{ymd}} is true. +// +// [Example: +// If dp represents 1970-01-01, the constructed weekday represents Thursday by storing 4 in wd_. +// —end example] + +#include +#include +#include + +#include "test_macros.h" + +int main() +{ + using sys_days = std::chrono::sys_days; + using days = std::chrono::days; + using weekday = std::chrono::weekday; + + ASSERT_NOEXCEPT(weekday{std::declval()}); + + { + constexpr sys_days sd{}; // 1-Jan-1970 was a Thursday + constexpr weekday wd{sd}; + + static_assert( wd.ok(), ""); + static_assert(static_cast(wd) == 4, ""); + } + + { + constexpr sys_days sd{days{10957+32}}; // 2-Feb-2000 was a Wednesday + constexpr weekday wd{sd}; + + static_assert( wd.ok(), ""); + static_assert(static_cast(wd) == 3, ""); + } + + + { + constexpr sys_days sd{days{-10957}}; // 2-Jan-1940 was a Tuesday + constexpr weekday wd{sd}; + + static_assert( wd.ok(), ""); + static_assert(static_cast(wd) == 2, ""); + } + + { + sys_days sd{days{-(10957+34)}}; // 29-Nov-1939 was a Wednesday + weekday wd{sd}; + + assert( wd.ok()); + assert(static_cast(wd) == 3); + } +} Index: test/std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/ctor.local_days.pass.cpp =================================================================== --- test/std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/ctor.local_days.pass.cpp +++ test/std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/ctor.local_days.pass.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 -// XFAIL: * // // class year_month_day; @@ -34,11 +33,53 @@ int main() { using year = std::chrono::year; - using month = std::chrono::month; using day = std::chrono::day; -// using local_days = std::chrono::local_days; + using local_days = std::chrono::local_days; + using days = std::chrono::days; using year_month_day = std::chrono::year_month_day; -// ASSERT_NOEXCEPT(year_month_day{std::declval()}); - assert(false); + ASSERT_NOEXCEPT(year_month_day{std::declval()}); + + { + constexpr local_days sd{}; + constexpr year_month_day ymd{sd}; + + static_assert( ymd.ok(), ""); + static_assert( ymd.year() == year{1970}, ""); + static_assert( ymd.month() == std::chrono::January, ""); + static_assert( ymd.day() == day{1}, ""); + } + + { + constexpr local_days sd{days{10957+32}}; + constexpr year_month_day ymd{sd}; + + static_assert( ymd.ok(), ""); + static_assert( ymd.year() == year{2000}, ""); + static_assert( ymd.month() == std::chrono::February, ""); + static_assert( ymd.day() == day{2}, ""); + } + + +// There's one more leap day between 1/1/40 and 1/1/70 +// when compared to 1/1/70 -> 1/1/2000 + { + constexpr local_days sd{days{-10957}}; + constexpr year_month_day ymd{sd}; + + static_assert( ymd.ok(), ""); + static_assert( ymd.year() == year{1940}, ""); + static_assert( ymd.month() == std::chrono::January, ""); + static_assert( ymd.day() == day{2}, ""); + } + + { + local_days sd{days{-(10957+34)}}; + year_month_day ymd{sd}; + + assert( ymd.ok()); + assert( ymd.year() == year{1939}); + assert( ymd.month() == std::chrono::November); + assert( ymd.day() == day{29}); + } } Index: test/std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/ctor.sys_days.pass.cpp =================================================================== --- test/std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/ctor.sys_days.pass.cpp +++ test/std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/ctor.sys_days.pass.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 -// XFAIL: * // // class year_month_day; @@ -14,8 +13,8 @@ // constexpr year_month_day(const sys_days& dp) noexcept; // -// Effects: Constructs an object of type year_month_day that corresponds -// to the date represented by dp +// Effects: Constructs an object of type year_month_day that corresponds +// to the date represented by dp. // // Remarks: For any value ymd of type year_month_day for which ymd.ok() is true, // ymd == year_month_day{sys_days{ymd}} is true. @@ -33,12 +32,53 @@ int main() { using year = std::chrono::year; - using month = std::chrono::month; using day = std::chrono::day; -// using sys_days = std::chrono::sys_days; + using sys_days = std::chrono::sys_days; + using days = std::chrono::days; using year_month_day = std::chrono::year_month_day; -// ASSERT_NOEXCEPT(year_month_day{std::declval()}); - assert(false); + ASSERT_NOEXCEPT(year_month_day{std::declval()}); + { + constexpr sys_days sd{}; + constexpr year_month_day ymd{sd}; + + static_assert( ymd.ok(), ""); + static_assert( ymd.year() == year{1970}, ""); + static_assert( ymd.month() == std::chrono::January, ""); + static_assert( ymd.day() == day{1}, ""); + } + + { + constexpr sys_days sd{days{10957+32}}; + constexpr year_month_day ymd{sd}; + + static_assert( ymd.ok(), ""); + static_assert( ymd.year() == year{2000}, ""); + static_assert( ymd.month() == std::chrono::February, ""); + static_assert( ymd.day() == day{2}, ""); + } + + +// There's one more leap day between 1/1/40 and 1/1/70 +// when compared to 1/1/70 -> 1/1/2000 + { + constexpr sys_days sd{days{-10957}}; + constexpr year_month_day ymd{sd}; + + static_assert( ymd.ok(), ""); + static_assert( ymd.year() == year{1940}, ""); + static_assert( ymd.month() == std::chrono::January, ""); + static_assert( ymd.day() == day{2}, ""); + } + + { + sys_days sd{days{-(10957+34)}}; + year_month_day ymd{sd}; + + assert( ymd.ok()); + assert( ymd.year() == year{1939}); + assert( ymd.month() == std::chrono::November); + assert( ymd.day() == day{29}); + } } Index: test/std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/ctor.year_month_day_last.pass.cpp =================================================================== --- test/std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/ctor.year_month_day_last.pass.cpp +++ test/std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/ctor.year_month_day_last.pass.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 -// XFAIL: * // // class year_month_day; @@ -33,10 +32,49 @@ using year = std::chrono::year; using month = std::chrono::month; using day = std::chrono::day; -// using year_month_day_last = std::chrono::year_month_day_last; + using month_day_last = std::chrono::month_day_last; + using year_month_day_last = std::chrono::year_month_day_last; using year_month_day = std::chrono::year_month_day; -// ASSERT_NOEXCEPT(year_month_day{std::declval()}); - assert(false); + ASSERT_NOEXCEPT(year_month_day{std::declval()}); + { + constexpr year_month_day_last ymdl{year{2019}, month_day_last{month{1}}}; + constexpr year_month_day ymd{ymdl}; + + static_assert( ymd.year() == year{2019}, ""); + static_assert( ymd.month() == month{1}, ""); + static_assert( ymd.day() == day{31}, ""); + static_assert( ymd.ok(), ""); + } + + { + constexpr year_month_day_last ymdl{year{1970}, month_day_last{month{4}}}; + constexpr year_month_day ymd{ymdl}; + + static_assert( ymd.year() == year{1970}, ""); + static_assert( ymd.month() == month{4}, ""); + static_assert( ymd.day() == day{30}, ""); + static_assert( ymd.ok(), ""); + } + + { + constexpr year_month_day_last ymdl{year{2000}, month_day_last{month{2}}}; + constexpr year_month_day ymd{ymdl}; + + static_assert( ymd.year() == year{2000}, ""); + static_assert( ymd.month() == month{2}, ""); + static_assert( ymd.day() == day{29}, ""); + static_assert( ymd.ok(), ""); + } + + { // Feb 1900 was NOT a leap year. + year_month_day_last ymdl{year{1900}, month_day_last{month{2}}}; + year_month_day ymd{ymdl}; + + assert( ymd.year() == year{1900}); + assert( ymd.month() == month{2}); + assert( ymd.day() == day{28}); + assert( ymd.ok()); + } } Index: test/std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/ok.pass.cpp =================================================================== --- test/std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/ok.pass.cpp +++ test/std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/ok.pass.cpp @@ -44,6 +44,37 @@ static_assert( year_month_day{year{2019}, January, day{1}}.ok(), ""); // All OK +// Some months have a 31st + static_assert( year_month_day{year{2020}, month{ 1}, day{31}}.ok(), ""); + static_assert(!year_month_day{year{2020}, month{ 2}, day{31}}.ok(), ""); + static_assert( year_month_day{year{2020}, month{ 3}, day{31}}.ok(), ""); + static_assert(!year_month_day{year{2020}, month{ 4}, day{31}}.ok(), ""); + static_assert( year_month_day{year{2020}, month{ 5}, day{31}}.ok(), ""); + static_assert(!year_month_day{year{2020}, month{ 6}, day{31}}.ok(), ""); + static_assert( year_month_day{year{2020}, month{ 7}, day{31}}.ok(), ""); + static_assert( year_month_day{year{2020}, month{ 8}, day{31}}.ok(), ""); + static_assert(!year_month_day{year{2020}, month{ 9}, day{31}}.ok(), ""); + static_assert( year_month_day{year{2020}, month{10}, day{31}}.ok(), ""); + static_assert(!year_month_day{year{2020}, month{11}, day{31}}.ok(), ""); + static_assert( year_month_day{year{2020}, month{12}, day{31}}.ok(), ""); + +// Everyone except FEB has a 30th + static_assert( year_month_day{year{2020}, month{ 1}, day{30}}.ok(), ""); + static_assert(!year_month_day{year{2020}, month{ 2}, day{30}}.ok(), ""); + static_assert( year_month_day{year{2020}, month{ 3}, day{30}}.ok(), ""); + static_assert( year_month_day{year{2020}, month{ 4}, day{30}}.ok(), ""); + static_assert( year_month_day{year{2020}, month{ 5}, day{30}}.ok(), ""); + static_assert( year_month_day{year{2020}, month{ 6}, day{30}}.ok(), ""); + static_assert( year_month_day{year{2020}, month{ 7}, day{30}}.ok(), ""); + static_assert( year_month_day{year{2020}, month{ 8}, day{30}}.ok(), ""); + static_assert( year_month_day{year{2020}, month{ 9}, day{30}}.ok(), ""); + static_assert( year_month_day{year{2020}, month{10}, day{30}}.ok(), ""); + static_assert( year_month_day{year{2020}, month{11}, day{30}}.ok(), ""); + static_assert( year_month_day{year{2020}, month{12}, day{30}}.ok(), ""); + + static_assert(!year_month_day{year{2019}, std::chrono::February, day{29}}.ok(), ""); // Not a leap year + static_assert( year_month_day{year{2020}, std::chrono::February, day{29}}.ok(), ""); // Ok; 2020 is a leap year + for (unsigned i = 0; i <= 50; ++i) { year_month_day ym{year{2019}, January, day{i}}; Index: test/std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/op.local_days.pass.cpp =================================================================== --- test/std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/op.local_days.pass.cpp +++ test/std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/op.local_days.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 + +// +// class year_month_day; + +// constexpr operator local_days() const noexcept; +// +// Returns: If ok(), returns a local_days holding a count of days from the +// local_days epoch to *this (a negative value if *this represents a date +// prior to the sys_days epoch). Otherwise, if y_.ok() && m_.ok() is true, +// returns a sys_days which is offset from sys_days{y_/m_/last} by the +// number of days d_ is offset from sys_days{y_/m_/last}.day(). Otherwise +// the value returned is unspecified. +// +// Remarks: A local_days in the range [days{-12687428}, days{11248737}] which +// is converted to a year_month_day shall have the same value when +// converted back to a sys_days. +// +// [Example: +// static_assert(year_month_day{local_days{2017y/January/0}} == 2016y/December/31); +// static_assert(year_month_day{local_days{2017y/January/31}} == 2017y/January/31); +// static_assert(year_month_day{local_days{2017y/January/32}} == 2017y/February/1); +// —end example] + +#include +#include +#include + +#include "test_macros.h" + +void RunTheExample() +{ + using namespace std::chrono; + + static_assert(year_month_day{local_days{2017y/January/0}} == 2016y/December/31); + static_assert(year_month_day{local_days{2017y/January/31}} == 2017y/January/31); + static_assert(year_month_day{local_days{2017y/January/32}} == 2017y/February/1); +} + +int main() +{ + using year = std::chrono::year; + using month = std::chrono::month; + using day = std::chrono::day; + using local_days = std::chrono::local_days; + using days = std::chrono::days; + using year_month_day = std::chrono::year_month_day; + + ASSERT_NOEXCEPT(local_days(std::declval())); + RunTheExample(); + + { + constexpr year_month_day ymd{year{1970}, month{1}, day{1}}; + constexpr local_days sd{ymd}; + + static_assert( sd.time_since_epoch() == days{0}, ""); + static_assert( year_month_day{sd} == ymd, ""); // and back + } + + { + constexpr year_month_day ymd{year{2000}, month{2}, day{2}}; + constexpr local_days sd{ymd}; + + static_assert( sd.time_since_epoch() == days{10957+32}, ""); + static_assert( year_month_day{sd} == ymd, ""); // and back + } + +// There's one more leap day between 1/1/40 and 1/1/70 +// when compared to 1/1/70 -> 1/1/2000 + { + constexpr year_month_day ymd{year{1940}, month{1}, day{2}}; + constexpr local_days sd{ymd}; + + static_assert( sd.time_since_epoch() == days{-10957}, ""); + static_assert( year_month_day{sd} == ymd, ""); // and back + } + + { + year_month_day ymd{year{1939}, month{11}, day{29}}; + local_days sd{ymd}; + + assert( sd.time_since_epoch() == days{-(10957+34)}); + assert( year_month_day{sd} == ymd); // and back + } + +} Index: test/std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/op.sys_days.pass.cpp =================================================================== --- test/std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/op.sys_days.pass.cpp +++ test/std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/op.sys_days.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 + +// +// class year_month_day; + +// constexpr operator sys_days() const noexcept; +// +// Returns: If ok(), returns a sys_days holding a count of days from the +// sys_days epoch to *this (a negative value if *this represents a date +// prior to the sys_days epoch). Otherwise, if y_.ok() && m_.ok() is true, +// returns a sys_days which is offset from sys_days{y_/m_/last} by the +// number of days d_ is offset from sys_days{y_/m_/last}.day(). Otherwise +// the value returned is unspecified. +// +// Remarks: A sys_days in the range [days{-12687428}, days{11248737}] which +// is converted to a year_month_day shall have the same value when +// converted back to a sys_days. +// +// [Example: +// static_assert(year_month_day{sys_days{2017y/January/0}} == 2016y/December/31); +// static_assert(year_month_day{sys_days{2017y/January/31}} == 2017y/January/31); +// static_assert(year_month_day{sys_days{2017y/January/32}} == 2017y/February/1); +// —end example] + +#include +#include +#include + +#include "test_macros.h" + +void RunTheExample() +{ + using namespace std::chrono; + + static_assert(year_month_day{sys_days{2017y/January/0}} == 2016y/December/31); + static_assert(year_month_day{sys_days{2017y/January/31}} == 2017y/January/31); + static_assert(year_month_day{sys_days{2017y/January/32}} == 2017y/February/1); +} + +int main() +{ + using year = std::chrono::year; + using month = std::chrono::month; + using day = std::chrono::day; + using sys_days = std::chrono::sys_days; + using days = std::chrono::days; + using year_month_day = std::chrono::year_month_day; + + ASSERT_NOEXCEPT(sys_days(std::declval())); + RunTheExample(); + + { + constexpr year_month_day ymd{year{1970}, month{1}, day{1}}; + constexpr sys_days sd{ymd}; + + static_assert( sd.time_since_epoch() == days{0}, ""); + static_assert( year_month_day{sd} == ymd, ""); // and back + } + + { + constexpr year_month_day ymd{year{2000}, month{2}, day{2}}; + constexpr sys_days sd{ymd}; + + static_assert( sd.time_since_epoch() == days{10957+32}, ""); + static_assert( year_month_day{sd} == ymd, ""); // and back + } + +// There's one more leap day between 1/1/40 and 1/1/70 +// when compared to 1/1/70 -> 1/1/2000 + { + constexpr year_month_day ymd{year{1940}, month{1}, day{2}}; + constexpr sys_days sd{ymd}; + + static_assert( sd.time_since_epoch() == days{-10957}, ""); + static_assert( year_month_day{sd} == ymd, ""); // and back + } + + { + year_month_day ymd{year{1939}, month{11}, day{29}}; + sys_days sd{ymd}; + + assert( sd.time_since_epoch() == days{-(10957+34)}); + assert( year_month_day{sd} == ymd); // and back + } + +} Index: test/std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/day.pass.cpp =================================================================== --- test/std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/day.pass.cpp +++ test/std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/day.pass.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 -// XFAIL: * // // class year_month_day_last; @@ -29,15 +28,24 @@ using month_day_last = std::chrono::month_day_last; using year_month_day_last = std::chrono::year_month_day_last; -// TODO: wait for calendar -// ASSERT_NOEXCEPT( std::declval().day()); -// ASSERT_SAME_TYPE(day, decltype(std::declval().day())); -// -// static_assert( year_month_day_last{}.day() == day{}, ""); + ASSERT_NOEXCEPT( std::declval().day()); + ASSERT_SAME_TYPE(day, decltype(std::declval().day())); - for (unsigned i = 1; i <= 12; ++i) - { - year_month_day_last ymd(year{1234}, month_day_last{month{i}}); - assert( static_cast(ymd.day()) == i); - } +// Some months have a 31st + static_assert( year_month_day_last{year{2020}, month_day_last{month{ 1}}}.day() == day{31}, ""); + static_assert( year_month_day_last{year{2020}, month_day_last{month{ 2}}}.day() == day{29}, ""); + static_assert( year_month_day_last{year{2020}, month_day_last{month{ 3}}}.day() == day{31}, ""); + static_assert( year_month_day_last{year{2020}, month_day_last{month{ 4}}}.day() == day{30}, ""); + static_assert( year_month_day_last{year{2020}, month_day_last{month{ 5}}}.day() == day{31}, ""); + static_assert( year_month_day_last{year{2020}, month_day_last{month{ 6}}}.day() == day{30}, ""); + static_assert( year_month_day_last{year{2020}, month_day_last{month{ 7}}}.day() == day{31}, ""); + static_assert( year_month_day_last{year{2020}, month_day_last{month{ 8}}}.day() == day{31}, ""); + static_assert( year_month_day_last{year{2020}, month_day_last{month{ 9}}}.day() == day{30}, ""); + static_assert( year_month_day_last{year{2020}, month_day_last{month{10}}}.day() == day{31}, ""); + static_assert( year_month_day_last{year{2020}, month_day_last{month{11}}}.day() == day{30}, ""); + static_assert( year_month_day_last{year{2020}, month_day_last{month{12}}}.day() == day{31}, ""); + + assert((year_month_day_last{year{2019}, month_day_last{month{ 2}}}.day() == day{28})); + assert((year_month_day_last{year{2020}, month_day_last{month{ 2}}}.day() == day{29})); + assert((year_month_day_last{year{2021}, month_day_last{month{ 2}}}.day() == day{28})); } Index: test/std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/op_local_days.pass.cpp =================================================================== --- test/std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/op_local_days.pass.cpp +++ test/std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/op_local_days.pass.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 -// XFAIL: * // // class year_month_day_last; @@ -24,13 +23,39 @@ int main() { using year = std::chrono::year; - using month = std::chrono::month; - using day = std::chrono::day; using month_day_last = std::chrono::month_day_last; using year_month_day_last = std::chrono::year_month_day_last; -// using sys_days = std::chrono::local_days; + using local_days = std::chrono::local_days; + using days = std::chrono::days; -// ASSERT_NOEXCEPT( static_cast(std::declval().year())); -// ASSERT_SAME_TYPE(year, decltype(static_cast(std::declval().year())); - assert(false); + ASSERT_NOEXCEPT( static_cast(std::declval())); + ASSERT_SAME_TYPE(local_days, decltype(static_cast(std::declval()))); + + { // Last day in Jan 1970 was the 31st + constexpr year_month_day_last ymdl{year{1970}, month_day_last{std::chrono::January}}; + constexpr local_days sd{ymdl}; + + static_assert(sd.time_since_epoch() == days{30}, ""); + } + + { + constexpr year_month_day_last ymdl{year{2000}, month_day_last{std::chrono::January}}; + constexpr local_days sd{ymdl}; + + static_assert(sd.time_since_epoch() == days{10957+30}, ""); + } + + { + constexpr year_month_day_last ymdl{year{1940}, month_day_last{std::chrono::January}}; + constexpr local_days sd{ymdl}; + + static_assert(sd.time_since_epoch() == days{-10957+29}, ""); + } + + { + year_month_day_last ymdl{year{1939}, month_day_last{std::chrono::November}}; + local_days sd{ymdl}; + + assert(sd.time_since_epoch() == days{-(10957+33)}); + } } Index: test/std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/op_sys_days.pass.cpp =================================================================== --- test/std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/op_sys_days.pass.cpp +++ test/std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/op_sys_days.pass.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 -// XFAIL: * // // class year_month_day_last; @@ -24,13 +23,39 @@ int main() { using year = std::chrono::year; - using month = std::chrono::month; - using day = std::chrono::day; using month_day_last = std::chrono::month_day_last; using year_month_day_last = std::chrono::year_month_day_last; -// using sys_days = std::chrono::sys_days; + using sys_days = std::chrono::sys_days; + using days = std::chrono::days; -// ASSERT_NOEXCEPT( static_cast(std::declval().year())); -// ASSERT_SAME_TYPE(year, decltype(static_cast(std::declval().year())); - assert(false); + ASSERT_NOEXCEPT( static_cast(std::declval())); + ASSERT_SAME_TYPE(sys_days, decltype(static_cast(std::declval()))); + + { // Last day in Jan 1970 was the 31st + constexpr year_month_day_last ymdl{year{1970}, month_day_last{std::chrono::January}}; + constexpr sys_days sd{ymdl}; + + static_assert(sd.time_since_epoch() == days{30}, ""); + } + + { + constexpr year_month_day_last ymdl{year{2000}, month_day_last{std::chrono::January}}; + constexpr sys_days sd{ymdl}; + + static_assert(sd.time_since_epoch() == days{10957+30}, ""); + } + + { + constexpr year_month_day_last ymdl{year{1940}, month_day_last{std::chrono::January}}; + constexpr sys_days sd{ymdl}; + + static_assert(sd.time_since_epoch() == days{-10957+29}, ""); + } + + { + year_month_day_last ymdl{year{1939}, month_day_last{std::chrono::November}}; + sys_days sd{ymdl}; + + assert(sd.time_since_epoch() == days{-(10957+33)}); + } } Index: test/std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/ctor.local_days.pass.cpp =================================================================== --- test/std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/ctor.local_days.pass.cpp +++ test/std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/ctor.local_days.pass.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 -// XFAIL: * // // class year_month_weekday; @@ -33,12 +32,64 @@ int main() { - using year = std::chrono::year; - using month = std::chrono::month; - using day = std::chrono::day; -// using local_days = std::chrono::local_days; + using year = std::chrono::year; + using days = std::chrono::days; + using local_days = std::chrono::local_days; + using weekday_indexed = std::chrono::weekday_indexed; using year_month_weekday = std::chrono::year_month_weekday; -// ASSERT_NOEXCEPT(year_month_weekday{std::declval()}); - assert(false); + ASSERT_NOEXCEPT(year_month_weekday{std::declval()}); + + { + constexpr local_days sd{}; // 1-Jan-1970 was a Thursday + constexpr year_month_weekday ymwd{sd}; + + static_assert( ymwd.ok(), ""); + static_assert( ymwd.year() == year{1970}, ""); + static_assert( ymwd.month() == std::chrono::January, ""); + static_assert( ymwd.weekday() == std::chrono::Thursday, ""); + static_assert( ymwd.index() == 1, ""); + static_assert( ymwd.weekday_indexed() == weekday_indexed{std::chrono::Thursday, 1}, ""); + static_assert( ymwd == year_month_weekday{local_days{ymwd}}, ""); // round trip + } + + { + constexpr local_days sd{days{10957+32}}; // 2-Feb-2000 was a Wednesday + constexpr year_month_weekday ymwd{sd}; + + static_assert( ymwd.ok(), ""); + static_assert( ymwd.year() == year{2000}, ""); + static_assert( ymwd.month() == std::chrono::February, ""); + static_assert( ymwd.weekday() == std::chrono::Wednesday, ""); + static_assert( ymwd.index() == 1, ""); + static_assert( ymwd.weekday_indexed() == weekday_indexed{std::chrono::Wednesday, 1}, ""); + static_assert( ymwd == year_month_weekday{local_days{ymwd}}, ""); // round trip + } + + + { + constexpr local_days sd{days{-10957}}; // 2-Jan-1940 was a Tuesday + constexpr year_month_weekday ymwd{sd}; + + static_assert( ymwd.ok(), ""); + static_assert( ymwd.year() == year{1940}, ""); + static_assert( ymwd.month() == std::chrono::January, ""); + static_assert( ymwd.weekday() == std::chrono::Tuesday, ""); + static_assert( ymwd.index() == 1, ""); + static_assert( ymwd.weekday_indexed() == weekday_indexed{std::chrono::Tuesday, 1}, ""); + static_assert( ymwd == year_month_weekday{local_days{ymwd}}, ""); // round trip + } + + { + local_days sd{days{-(10957+34)}}; // 29-Nov-1939 was a Wednesday + year_month_weekday ymwd{sd}; + + assert( ymwd.ok()); + assert( ymwd.year() == year{1939}); + assert( ymwd.month() == std::chrono::November); + assert( ymwd.weekday() == std::chrono::Wednesday); + assert( ymwd.index() == 5); + assert((ymwd.weekday_indexed() == weekday_indexed{std::chrono::Wednesday, 5})); + assert( ymwd == year_month_weekday{local_days{ymwd}}); // round trip + } } Index: test/std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/ctor.sys_days.pass.cpp =================================================================== --- test/std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/ctor.sys_days.pass.cpp +++ test/std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/ctor.sys_days.pass.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 -// XFAIL: * // // class year_month_weekday; @@ -32,12 +31,64 @@ int main() { - using year = std::chrono::year; - using month = std::chrono::month; - using day = std::chrono::day; -// using sys_days = std::chrono::sys_days; + using year = std::chrono::year; + using days = std::chrono::days; + using sys_days = std::chrono::sys_days; + using weekday_indexed = std::chrono::weekday_indexed; using year_month_weekday = std::chrono::year_month_weekday; -// ASSERT_NOEXCEPT(year_month_weekday{std::declval()}); - assert(false); + ASSERT_NOEXCEPT(year_month_weekday{std::declval()}); + + { + constexpr sys_days sd{}; // 1-Jan-1970 was a Thursday + constexpr year_month_weekday ymwd{sd}; + + static_assert( ymwd.ok(), ""); + static_assert( ymwd.year() == year{1970}, ""); + static_assert( ymwd.month() == std::chrono::January, ""); + static_assert( ymwd.weekday() == std::chrono::Thursday, ""); + static_assert( ymwd.index() == 1, ""); + static_assert( ymwd.weekday_indexed() == weekday_indexed{std::chrono::Thursday, 1}, ""); + static_assert( ymwd == year_month_weekday{sys_days{ymwd}}, ""); // round trip + } + + { + constexpr sys_days sd{days{10957+32}}; // 2-Feb-2000 was a Wednesday + constexpr year_month_weekday ymwd{sd}; + + static_assert( ymwd.ok(), ""); + static_assert( ymwd.year() == year{2000}, ""); + static_assert( ymwd.month() == std::chrono::February, ""); + static_assert( ymwd.weekday() == std::chrono::Wednesday, ""); + static_assert( ymwd.index() == 1, ""); + static_assert( ymwd.weekday_indexed() == weekday_indexed{std::chrono::Wednesday, 1}, ""); + static_assert( ymwd == year_month_weekday{sys_days{ymwd}}, ""); // round trip + } + + + { + constexpr sys_days sd{days{-10957}}; // 2-Jan-1940 was a Tuesday + constexpr year_month_weekday ymwd{sd}; + + static_assert( ymwd.ok(), ""); + static_assert( ymwd.year() == year{1940}, ""); + static_assert( ymwd.month() == std::chrono::January, ""); + static_assert( ymwd.weekday() == std::chrono::Tuesday, ""); + static_assert( ymwd.index() == 1, ""); + static_assert( ymwd.weekday_indexed() == weekday_indexed{std::chrono::Tuesday, 1}, ""); + static_assert( ymwd == year_month_weekday{sys_days{ymwd}}, ""); // round trip + } + + { + sys_days sd{days{-(10957+34)}}; // 29-Nov-1939 was a Wednesday + year_month_weekday ymwd{sd}; + + assert( ymwd.ok()); + assert( ymwd.year() == year{1939}); + assert( ymwd.month() == std::chrono::November); + assert( ymwd.weekday() == std::chrono::Wednesday); + assert( ymwd.index() == 5); + assert((ymwd.weekday_indexed() == weekday_indexed{std::chrono::Wednesday, 5})); + assert( ymwd == year_month_weekday{sys_days{ymwd}}); // round trip + } } Index: test/std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/ctor.year_month_day_last.pass.cpp =================================================================== --- test/std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/ctor.year_month_day_last.pass.cpp +++ test/std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/ctor.year_month_day_last.pass.cpp @@ -1,41 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 -// XFAIL: * - -// -// class year_month_weekday; - -// constexpr year_month_weekday(const year_month_weekday_last& ymdl) noexcept; -// -// Effects: Constructs an object of type year_month_weekday by initializing -// y_ with ymdl.year(), m_ with ymdl.month(), and d_ with ymdl.day(). -// -// constexpr chrono::year year() const noexcept; -// constexpr chrono::month month() const noexcept; -// constexpr chrono::day day() const noexcept; -// constexpr bool ok() const noexcept; - -#include -#include -#include - -#include "test_macros.h" - -int main() -{ - using year = std::chrono::year; - using month = std::chrono::month; - using day = std::chrono::day; - using year_month_weekday_last = std::chrono::year_month_weekday_last; - using year_month_weekday = std::chrono::year_month_weekday; - - ASSERT_NOEXCEPT(year_month_weekday{std::declval()}); - -} Index: test/std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/op.local_days.pass.cpp =================================================================== --- test/std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/op.local_days.pass.cpp +++ test/std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/op.local_days.pass.cpp @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 + +// +// class year_month_weekday; + +// explicit constexpr operator local_days() const noexcept; +// +// Returns: If y_.ok() && m_.ok() && wdi_.weekday().ok(), returns a +// sys_days that represents the date (index() - 1) * 7 days after the first +// weekday() of year()/month(). If index() is 0 the returned sys_days +// represents the date 7 days prior to the first weekday() of +// year()/month(). Otherwise the returned value is unspecified. +// + +#include +#include +#include + +#include "test_macros.h" + +int main() +{ + using year = std::chrono::year; + using month = std::chrono::month; + using weekday_indexed = std::chrono::weekday_indexed; + using local_days = std::chrono::local_days; + using days = std::chrono::days; + using year_month_weekday = std::chrono::year_month_weekday; + + ASSERT_NOEXCEPT(local_days(std::declval())); + + { + constexpr year_month_weekday ymwd{year{1970}, month{1}, weekday_indexed{std::chrono::Thursday, 1}}; + constexpr local_days sd{ymwd}; + + static_assert( sd.time_since_epoch() == days{0}, ""); + static_assert( year_month_weekday{sd} == ymwd, ""); // and back + } + + { + constexpr year_month_weekday ymwd{year{2000}, month{2}, weekday_indexed{std::chrono::Wednesday, 1}}; + constexpr local_days sd{ymwd}; + + static_assert( sd.time_since_epoch() == days{10957+32}, ""); + static_assert( year_month_weekday{sd} == ymwd, ""); // and back + } + +// There's one more leap day between 1/1/40 and 1/1/70 +// when compared to 1/1/70 -> 1/1/2000 + { + constexpr year_month_weekday ymwd{year{1940}, month{1},weekday_indexed{std::chrono::Tuesday, 1}}; + constexpr local_days sd{ymwd}; + + static_assert( sd.time_since_epoch() == days{-10957}, ""); + static_assert( year_month_weekday{sd} == ymwd, ""); // and back + } + + { + year_month_weekday ymwd{year{1939}, month{11}, weekday_indexed{std::chrono::Wednesday, 5}}; + local_days sd{ymwd}; + + assert( sd.time_since_epoch() == days{-(10957+34)}); + assert( year_month_weekday{sd} == ymwd); // and back + } + +} Index: test/std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/op.sys_days.pass.cpp =================================================================== --- test/std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/op.sys_days.pass.cpp +++ test/std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/op.sys_days.pass.cpp @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 + +// +// class year_month_weekday; + +// constexpr operator sys_days() const noexcept; +// +// Returns: If y_.ok() && m_.ok() && wdi_.weekday().ok(), returns a +// sys_days that represents the date (index() - 1) * 7 days after the first +// weekday() of year()/month(). If index() is 0 the returned sys_days +// represents the date 7 days prior to the first weekday() of +// year()/month(). Otherwise the returned value is unspecified. +// + +#include +#include +#include + +#include "test_macros.h" + +int main() +{ + using year = std::chrono::year; + using month = std::chrono::month; + using weekday_indexed = std::chrono::weekday_indexed; + using sys_days = std::chrono::sys_days; + using days = std::chrono::days; + using year_month_weekday = std::chrono::year_month_weekday; + + ASSERT_NOEXCEPT(sys_days(std::declval())); + + { + constexpr year_month_weekday ymwd{year{1970}, month{1}, weekday_indexed{std::chrono::Thursday, 1}}; + constexpr sys_days sd{ymwd}; + + static_assert( sd.time_since_epoch() == days{0}, ""); + static_assert( year_month_weekday{sd} == ymwd, ""); // and back + } + + { + constexpr year_month_weekday ymwd{year{2000}, month{2}, weekday_indexed{std::chrono::Wednesday, 1}}; + constexpr sys_days sd{ymwd}; + + static_assert( sd.time_since_epoch() == days{10957+32}, ""); + static_assert( year_month_weekday{sd} == ymwd, ""); // and back + } + +// There's one more leap day between 1/1/40 and 1/1/70 +// when compared to 1/1/70 -> 1/1/2000 + { + constexpr year_month_weekday ymwd{year{1940}, month{1},weekday_indexed{std::chrono::Tuesday, 1}}; + constexpr sys_days sd{ymwd}; + + static_assert( sd.time_since_epoch() == days{-10957}, ""); + static_assert( year_month_weekday{sd} == ymwd, ""); // and back + } + + { + year_month_weekday ymwd{year{1939}, month{11}, weekday_indexed{std::chrono::Wednesday, 5}}; + sys_days sd{ymwd}; + + assert( sd.time_since_epoch() == days{-(10957+34)}); + assert( year_month_weekday{sd} == ymwd); // and back + } + +} Index: test/std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.members/op_local_days.pass.cpp =================================================================== --- test/std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.members/op_local_days.pass.cpp +++ test/std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.members/op_local_days.pass.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 -// XFAIL: * // // class year_month_day_last; @@ -24,12 +23,39 @@ int main() { using year = std::chrono::year; - using month = std::chrono::month; - using day = std::chrono::day; using month_day_last = std::chrono::month_day_last; using year_month_day_last = std::chrono::year_month_day_last; - using sys_days = std::chrono::local_days; + using local_days = std::chrono::local_days; + using days = std::chrono::days; - ASSERT_NOEXCEPT( static_cast(std::declval().year())); - ASSERT_SAME_TYPE(year, decltype(static_cast(std::declval().year())); + ASSERT_NOEXCEPT( static_cast(std::declval())); + ASSERT_SAME_TYPE(local_days, decltype(static_cast(std::declval()))); + + { // Last day in Jan 1970 was the 31st + constexpr year_month_day_last ymdl{year{1970}, month_day_last{std::chrono::January}}; + constexpr local_days sd{ymdl}; + + static_assert(sd.time_since_epoch() == days{30}, ""); + } + + { + constexpr year_month_day_last ymdl{year{2000}, month_day_last{std::chrono::January}}; + constexpr local_days sd{ymdl}; + + static_assert(sd.time_since_epoch() == days{10957+30}, ""); + } + + { + constexpr year_month_day_last ymdl{year{1940}, month_day_last{std::chrono::January}}; + constexpr local_days sd{ymdl}; + + static_assert(sd.time_since_epoch() == days{-10957+29}, ""); + } + + { + year_month_day_last ymdl{year{1939}, month_day_last{std::chrono::November}}; + local_days sd{ymdl}; + + assert(sd.time_since_epoch() == days{-(10957+33)}); + } } Index: test/std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.members/op_sys_days.pass.cpp =================================================================== --- test/std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.members/op_sys_days.pass.cpp +++ test/std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.members/op_sys_days.pass.cpp @@ -7,13 +7,13 @@ // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 -// XFAIL: * // -// class year_month_day_last; +// class year_month_weekday_last; // constexpr operator sys_days() const noexcept; -// Returns: sys_days{year()/month()/day()}. +// Returns: If ok() == true, returns a sys_days that represents the last weekday() +// of year()/month(). Otherwise the returned value is unspecified. #include #include @@ -21,16 +21,49 @@ #include "test_macros.h" +#include + int main() { - using year = std::chrono::year; - using month = std::chrono::month; - using day = std::chrono::day; - using month_day_last = std::chrono::month_day_last; - using year_month_day_last = std::chrono::year_month_day_last; - using sys_days = std::chrono::sys_days; + using year = std::chrono::year; + using month = std::chrono::month; + using year_month_weekday_last = std::chrono::year_month_weekday_last; + using sys_days = std::chrono::sys_days; + using days = std::chrono::days; + using weekday = std::chrono::weekday; + using weekday_last = std::chrono::weekday_last; - ASSERT_NOEXCEPT( static_cast(std::declval().year())); - ASSERT_SAME_TYPE(year, decltype(static_cast(std::declval().year())); + ASSERT_NOEXCEPT( static_cast(std::declval())); + ASSERT_SAME_TYPE(sys_days, decltype(static_cast(std::declval()))); + constexpr month January = std::chrono::January; + constexpr weekday Tuesday = std::chrono::Tuesday; + + { // Last Tuesday in Jan 1970 was the 27th + constexpr year_month_weekday_last ymwdl{year{1970}, January, weekday_last{Tuesday}}; + constexpr sys_days sd{ymwdl}; + + static_assert(sd.time_since_epoch() == days{26}, ""); + } + + { // Last Tuesday in Jan 2000 was the 25th + constexpr year_month_weekday_last ymwdl{year{2000}, January, weekday_last{Tuesday}}; + constexpr sys_days sd{ymwdl}; + + static_assert(sd.time_since_epoch() == days{10957+24}, ""); + } + + { // Last Tuesday in Jan 1940 was the 30th + constexpr year_month_weekday_last ymwdl{year{1940}, January, weekday_last{Tuesday}}; + constexpr sys_days sd{ymwdl}; + + static_assert(sd.time_since_epoch() == days{-10958+29}, ""); + } + + { // Last Tuesday in Nov 1939 was the 28th + year_month_weekday_last ymdl{year{1939}, std::chrono::November, weekday_last{Tuesday}}; + sys_days sd{ymdl}; + + assert(sd.time_since_epoch() == days{-(10957+35)}); + } } Index: test/std/utilities/time/time.clock/time.clock.system/local_time.types.pass.cpp =================================================================== --- test/std/utilities/time/time.clock/time.clock.system/local_time.types.pass.cpp +++ test/std/utilities/time/time.clock/time.clock.system/local_time.types.pass.cpp @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 + +// + +// struct local_t {}; +// template +// using local_time = time_point; +// using local_seconds = sys_time; +// using local_days = sys_time; + +// [Example: +// sys_seconds{sys_days{1970y/January/1}}.time_since_epoch() is 0s. +// sys_seconds{sys_days{2000y/January/1}}.time_since_epoch() is 946’684’800s, which is 10’957 * 86’400s. +// —end example] + + +#include +#include + +#include "test_macros.h" + +int main() +{ + using local_t = std::chrono::local_t; + using year = std::chrono::year; + + using seconds = std::chrono::seconds; + using minutes = std::chrono::minutes; + using days = std::chrono::days; + + using local_seconds = std::chrono::local_seconds; + using local_minutes = std::chrono::local_time; + using local_days = std::chrono::local_days; + + constexpr std::chrono::month January = std::chrono::January; + + ASSERT_SAME_TYPE(std::chrono::local_time, local_seconds); + ASSERT_SAME_TYPE(std::chrono::local_time, local_days); + +// Test the long form, too + ASSERT_SAME_TYPE(std::chrono::time_point, local_seconds); + ASSERT_SAME_TYPE(std::chrono::time_point, local_minutes); + ASSERT_SAME_TYPE(std::chrono::time_point, local_days); + +// Test some well known values + local_days d0 = local_days{year{1970}/January/1}; + local_days d1 = local_days{year{2000}/January/1}; + ASSERT_SAME_TYPE(decltype(d0.time_since_epoch()), days); + assert( d0.time_since_epoch().count() == 0); + assert( d1.time_since_epoch().count() == 10957); + + local_seconds s0{d0}; + local_seconds s1{d1}; + ASSERT_SAME_TYPE(decltype(s0.time_since_epoch()), seconds); + assert( s0.time_since_epoch().count() == 0); + assert( s1.time_since_epoch().count() == 946684800L); +} Index: test/std/utilities/time/time.clock/time.clock.system/sys.time.types.pass.cpp =================================================================== --- test/std/utilities/time/time.clock/time.clock.system/sys.time.types.pass.cpp +++ test/std/utilities/time/time.clock/time.clock.system/sys.time.types.pass.cpp @@ -0,0 +1,64 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 + +// + +// template +// using sys_time = time_point; +// using sys_seconds = sys_time; +// using sys_days = sys_time; + +// [Example: +// sys_seconds{sys_days{1970y/January/1}}.time_since_epoch() is 0s. +// sys_seconds{sys_days{2000y/January/1}}.time_since_epoch() is 946’684’800s, which is 10’957 * 86’400s. +// —end example] + + +#include +#include + +#include "test_macros.h" + +int main() +{ + using system_clock = std::chrono::system_clock; + using year = std::chrono::year; + + using seconds = std::chrono::seconds; + using minutes = std::chrono::minutes; + using days = std::chrono::days; + + using sys_seconds = std::chrono::sys_seconds; + using sys_minutes = std::chrono::sys_time; + using sys_days = std::chrono::sys_days; + + constexpr std::chrono::month January = std::chrono::January; + + ASSERT_SAME_TYPE(std::chrono::sys_time, sys_seconds); + ASSERT_SAME_TYPE(std::chrono::sys_time, sys_days); + +// Test the long form, too + ASSERT_SAME_TYPE(std::chrono::time_point, sys_seconds); + ASSERT_SAME_TYPE(std::chrono::time_point, sys_minutes); + ASSERT_SAME_TYPE(std::chrono::time_point, sys_days); + +// Test some well known values + sys_days d0 = sys_days{year{1970}/January/1}; + sys_days d1 = sys_days{year{2000}/January/1}; + ASSERT_SAME_TYPE(decltype(d0.time_since_epoch()), days); + assert( d0.time_since_epoch().count() == 0); + assert( d1.time_since_epoch().count() == 10957); + + sys_seconds s0{d0}; + sys_seconds s1{d1}; + ASSERT_SAME_TYPE(decltype(s0.time_since_epoch()), seconds); + assert( s0.time_since_epoch().count() == 0); + assert( s1.time_since_epoch().count() == 946684800L); +}