diff --git a/stl/inc/chrono b/stl/inc/chrono index 7927b883277..25d3b2ac196 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -1394,35 +1394,31 @@ namespace chrono { // courtesy of Howard Hinnant // https://howardhinnant.github.io/date_algorithms.html#civil_from_days _NODISCARD static constexpr year_month_day _Civil_from_days(int _Tp) noexcept { - static_assert(numeric_limits::digits >= 18); - static_assert(numeric_limits::digits >= 20); - const int _Zx = _Tp + 719468; // Shift epoch to 0000-03-01 - const int _Era = (_Zx >= 0 ? _Zx : _Zx - 146096) / 146097; - const unsigned int _Day_of_era = static_cast(_Zx - _Era * 146097); // [0, 146096] - const unsigned int _Year_of_era = - (_Day_of_era - _Day_of_era / 1460 + _Day_of_era / 36524 - _Day_of_era / 146096) / 365; // [0, 399] - const int _Year = static_cast(_Year_of_era) + _Era * 400; // Where March is the first month - const unsigned int _Day_of_year = - _Day_of_era - (365 * _Year_of_era + _Year_of_era / 4 - _Year_of_era / 100); // [0, 365] - const unsigned int _Mp = (5 * _Day_of_year + 2) / 153; // [0, 11] - const unsigned int _Day = _Day_of_year - (153 * _Mp + 2) / 5 + 1; // [1, 31] - const unsigned int _Month = _Mp + (_Mp < 10 ? 3 : static_cast(-9)); // [1, 12] + static_assert(numeric_limits::digits >= 32); + static_assert(numeric_limits::digits >= 26); + const int _Zx = _Tp + 719468; // Shift epoch to 0000-03-01 + const int _Century = (_Zx >= 0 ? 4 * _Zx + 3 : 4 * _Zx - 146093) / 146097; + const unsigned int _Day_of_century = + static_cast(_Zx - ((146097 * _Century) >> 2)); // [0, 36524] + const unsigned int _Year_of_century = (91867 * (_Day_of_century + 1)) >> 25; // [0, 99] + const int _Year = static_cast(_Year_of_century) + _Century * 100; // Where March is the first month + const unsigned int _Day_of_year = _Day_of_century - ((1461 * _Year_of_century) >> 2); // [0, 365] + const unsigned int _Mp = (535 * _Day_of_year + 333) >> 14; // [0, 11] + const unsigned int _Day = _Day_of_year - ((979 * _Mp + 19) >> 5) + 1; // [1, 31] + const unsigned int _Month = _Mp + (_Mp < 10 ? 3 : static_cast(-9)); // [1, 12] return year_month_day{_CHRONO year{_Year + (_Month <= 2)}, _CHRONO month{_Month}, _CHRONO day{_Day}}; } // courtesy of Howard Hinnant // https://howardhinnant.github.io/date_algorithms.html#days_from_civil _NODISCARD constexpr days _Days_from_civil() const noexcept { static_assert(numeric_limits::digits >= 18); - static_assert(numeric_limits::digits >= 20); - const int _Ye = static_cast(_Year) - (_Month <= _CHRONO month{2}); - const unsigned int _Mo = static_cast(_Month); - const int _Era = (_Ye >= 0 ? _Ye : _Ye - 399) / 400; - const unsigned int _Year_of_era = static_cast(_Ye - _Era * 400); // [0, 399] - const unsigned int _Day_of_year = (153 * (_Mo + (_Mo > 2 ? static_cast(-3) : 9)) + 2) / 5 - + static_cast(_Day) - 1; // [0, 365] - const unsigned int _Day_of_era = - _Year_of_era * 365 + _Year_of_era / 4 - _Year_of_era / 100 + _Day_of_year; // [0, 146096] - return days{_Era * 146097 + static_cast(_Day_of_era) - 719468}; + static_assert(numeric_limits::digits >= 26); + const unsigned int _Mo = static_cast(_Month); // [1, 12] + const int _Ye = static_cast(_Year) - (_Mo <= 2); + const int _Century = (_Ye >= 0 ? _Ye : _Ye - 99) / 100; + const unsigned int _Mp = _Mo + (_Mo > 2 ? static_cast(-3) : 9); // [0, 11] + const int _Day_of_year = static_cast(((979 * _Mp + 19) >> 5) + static_cast(_Day)) - 1; + return days{((_Ye * 1461) >> 2) - _Century + (_Century >> 2) + _Day_of_year - 719468}; } }; diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_dates/test.cpp b/tests/std/tests/P0355R7_calendars_and_time_zones_dates/test.cpp index 90d6d7ad946..4bb31c8a863 100644 --- a/tests/std/tests/P0355R7_calendars_and_time_zones_dates/test.cpp +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_dates/test.cpp @@ -700,6 +700,190 @@ constexpr void year_month_day_test() { } } } + + if (is_constant_evaluated()) { + // clang-format off + static_assert(sys_days{ 2000y/ 1/ 1} == sys_days{days{ 10957}}); + static_assert(sys_days{ 2000y/ 1/31} == sys_days{days{ 10987}}); + static_assert(sys_days{ 2000y/ 2/ 1} == sys_days{days{ 10988}}); + static_assert(sys_days{ 2000y/ 2/29} == sys_days{days{ 11016}}); + static_assert(sys_days{ 2000y/ 3/ 1} == sys_days{days{ 11017}}); + static_assert(sys_days{ 2000y/ 3/31} == sys_days{days{ 11047}}); + static_assert(sys_days{ 2000y/ 4/ 1} == sys_days{days{ 11048}}); + static_assert(sys_days{ 2000y/ 4/30} == sys_days{days{ 11077}}); + static_assert(sys_days{ 2000y/ 5/ 1} == sys_days{days{ 11078}}); + static_assert(sys_days{ 2000y/ 5/31} == sys_days{days{ 11108}}); + static_assert(sys_days{ 2000y/ 6/ 1} == sys_days{days{ 11109}}); + static_assert(sys_days{ 2000y/ 6/30} == sys_days{days{ 11138}}); + static_assert(sys_days{ 2000y/ 7/ 1} == sys_days{days{ 11139}}); + static_assert(sys_days{ 2000y/ 7/31} == sys_days{days{ 11169}}); + static_assert(sys_days{ 2000y/ 8/ 1} == sys_days{days{ 11170}}); + static_assert(sys_days{ 2000y/ 8/31} == sys_days{days{ 11200}}); + static_assert(sys_days{ 2000y/ 9/ 1} == sys_days{days{ 11201}}); + static_assert(sys_days{ 2000y/ 9/30} == sys_days{days{ 11230}}); + static_assert(sys_days{ 2000y/10/ 1} == sys_days{days{ 11231}}); + static_assert(sys_days{ 2000y/10/31} == sys_days{days{ 11261}}); + static_assert(sys_days{ 2000y/11/ 1} == sys_days{days{ 11262}}); + static_assert(sys_days{ 2000y/11/30} == sys_days{days{ 11291}}); + static_assert(sys_days{ 2000y/12/ 1} == sys_days{days{ 11292}}); + static_assert(sys_days{ 2000y/12/31} == sys_days{days{ 11322}}); + static_assert(sys_days{ -400y/ 2/29} == sys_days{days{ -865566}}); + static_assert(sys_days{ -400y/ 3/ 1} == sys_days{days{ -865565}}); + static_assert(sys_days{ -1y/ 2/28} == sys_days{days{ -719835}}); + static_assert(sys_days{ -1y/ 3/ 1} == sys_days{days{ -719834}}); + static_assert(sys_days{ -1y/12/31} == sys_days{days{ -719529}}); + static_assert(sys_days{ 0y/ 1/ 1} == sys_days{days{ -719528}}); + static_assert(sys_days{ 0y/ 2/29} == sys_days{days{ -719469}}); + static_assert(sys_days{ 0y/ 3/ 1} == sys_days{days{ -719468}}); + static_assert(sys_days{ 1900y/ 3/ 1} == sys_days{days{ -25508}}); + static_assert(sys_days{ 1901y/ 2/28} == sys_days{days{ -25144}}); + static_assert(sys_days{ 1903y/ 3/ 1} == sys_days{days{ -24413}}); + static_assert(sys_days{ 1904y/ 2/29} == sys_days{days{ -24048}}); + static_assert(sys_days{ 1996y/ 3/ 1} == sys_days{days{ 9556}}); + static_assert(sys_days{ 1997y/ 2/28} == sys_days{days{ 9920}}); + static_assert(sys_days{ 1999y/ 3/ 1} == sys_days{days{ 10651}}); + static_assert(sys_days{ 2000y/ 2/29} == sys_days{days{ 11016}}); + static_assert(sys_days{ 2000y/ 3/ 1} == sys_days{days{ 11017}}); + static_assert(sys_days{ 2001y/ 2/28} == sys_days{days{ 11381}}); + static_assert(sys_days{ 2003y/ 3/ 1} == sys_days{days{ 12112}}); + static_assert(sys_days{ 2004y/ 2/29} == sys_days{days{ 12477}}); + static_assert(sys_days{ 2096y/ 3/ 1} == sys_days{days{ 46081}}); + static_assert(sys_days{ 2097y/ 2/28} == sys_days{days{ 46445}}); + static_assert(sys_days{ 2099y/ 3/ 1} == sys_days{days{ 47176}}); + static_assert(sys_days{ 2100y/ 2/28} == sys_days{days{ 47540}}); + static_assert(sys_days{-32767y/ 1/ 1} == sys_days{days{-12687428}}); + static_assert(sys_days{ 32767y/12/31} == sys_days{days{ 11248737}}); + + static_assert( 2000y/ 1/ 1 == year_month_day{sys_days{days{ 10957}}}); + static_assert( 2000y/ 1/31 == year_month_day{sys_days{days{ 10987}}}); + static_assert( 2000y/ 2/ 1 == year_month_day{sys_days{days{ 10988}}}); + static_assert( 2000y/ 2/29 == year_month_day{sys_days{days{ 11016}}}); + static_assert( 2000y/ 3/ 1 == year_month_day{sys_days{days{ 11017}}}); + static_assert( 2000y/ 3/31 == year_month_day{sys_days{days{ 11047}}}); + static_assert( 2000y/ 4/ 1 == year_month_day{sys_days{days{ 11048}}}); + static_assert( 2000y/ 4/30 == year_month_day{sys_days{days{ 11077}}}); + static_assert( 2000y/ 5/ 1 == year_month_day{sys_days{days{ 11078}}}); + static_assert( 2000y/ 5/31 == year_month_day{sys_days{days{ 11108}}}); + static_assert( 2000y/ 6/ 1 == year_month_day{sys_days{days{ 11109}}}); + static_assert( 2000y/ 6/30 == year_month_day{sys_days{days{ 11138}}}); + static_assert( 2000y/ 7/ 1 == year_month_day{sys_days{days{ 11139}}}); + static_assert( 2000y/ 7/31 == year_month_day{sys_days{days{ 11169}}}); + static_assert( 2000y/ 8/ 1 == year_month_day{sys_days{days{ 11170}}}); + static_assert( 2000y/ 8/31 == year_month_day{sys_days{days{ 11200}}}); + static_assert( 2000y/ 9/ 1 == year_month_day{sys_days{days{ 11201}}}); + static_assert( 2000y/ 9/30 == year_month_day{sys_days{days{ 11230}}}); + static_assert( 2000y/10/ 1 == year_month_day{sys_days{days{ 11231}}}); + static_assert( 2000y/10/31 == year_month_day{sys_days{days{ 11261}}}); + static_assert( 2000y/11/ 1 == year_month_day{sys_days{days{ 11262}}}); + static_assert( 2000y/11/30 == year_month_day{sys_days{days{ 11291}}}); + static_assert( 2000y/12/ 1 == year_month_day{sys_days{days{ 11292}}}); + static_assert( 2000y/12/31 == year_month_day{sys_days{days{ 11322}}}); + static_assert( -400y/ 2/29 == year_month_day{sys_days{days{ -865566}}}); + static_assert( -400y/ 3/ 1 == year_month_day{sys_days{days{ -865565}}}); + static_assert( -1y/ 2/28 == year_month_day{sys_days{days{ -719835}}}); + static_assert( -1y/ 3/ 1 == year_month_day{sys_days{days{ -719834}}}); + static_assert( -1y/12/31 == year_month_day{sys_days{days{ -719529}}}); + static_assert( 0y/ 1/ 1 == year_month_day{sys_days{days{ -719528}}}); + static_assert( 0y/ 2/29 == year_month_day{sys_days{days{ -719469}}}); + static_assert( 0y/ 3/ 1 == year_month_day{sys_days{days{ -719468}}}); + static_assert( 1900y/ 3/ 1 == year_month_day{sys_days{days{ -25508}}}); + static_assert( 1901y/ 2/28 == year_month_day{sys_days{days{ -25144}}}); + static_assert( 1903y/ 3/ 1 == year_month_day{sys_days{days{ -24413}}}); + static_assert( 1904y/ 2/29 == year_month_day{sys_days{days{ -24048}}}); + static_assert( 1996y/ 3/ 1 == year_month_day{sys_days{days{ 9556}}}); + static_assert( 1997y/ 2/28 == year_month_day{sys_days{days{ 9920}}}); + static_assert( 1999y/ 3/ 1 == year_month_day{sys_days{days{ 10651}}}); + static_assert( 2000y/ 2/29 == year_month_day{sys_days{days{ 11016}}}); + static_assert( 2000y/ 3/ 1 == year_month_day{sys_days{days{ 11017}}}); + static_assert( 2001y/ 2/28 == year_month_day{sys_days{days{ 11381}}}); + static_assert( 2003y/ 3/ 1 == year_month_day{sys_days{days{ 12112}}}); + static_assert( 2004y/ 2/29 == year_month_day{sys_days{days{ 12477}}}); + static_assert( 2096y/ 3/ 1 == year_month_day{sys_days{days{ 46081}}}); + static_assert( 2097y/ 2/28 == year_month_day{sys_days{days{ 46445}}}); + static_assert( 2099y/ 3/ 1 == year_month_day{sys_days{days{ 47176}}}); + static_assert( 2100y/ 2/28 == year_month_day{sys_days{days{ 47540}}}); + static_assert(-32767y/ 1/ 1 == year_month_day{sys_days{days{-12687428}}}); + static_assert( 32767y/12/31 == year_month_day{sys_days{days{ 11248737}}}); + + static_assert(sys_days{ 2000y/ 1/ 0} == sys_days{days{ 10956}}); + static_assert(sys_days{ 2000y/ 1/255} == sys_days{days{ 11211}}); + static_assert(sys_days{ 2000y/ 2/ 0} == sys_days{days{ 10987}}); + static_assert(sys_days{ 2000y/ 2/255} == sys_days{days{ 11242}}); + static_assert(sys_days{ 2000y/ 3/ 0} == sys_days{days{ 11016}}); + static_assert(sys_days{ 2000y/ 3/255} == sys_days{days{ 11271}}); + static_assert(sys_days{ 2000y/ 4/ 0} == sys_days{days{ 11047}}); + static_assert(sys_days{ 2000y/ 4/255} == sys_days{days{ 11302}}); + static_assert(sys_days{ 2000y/ 5/ 0} == sys_days{days{ 11077}}); + static_assert(sys_days{ 2000y/ 5/255} == sys_days{days{ 11332}}); + static_assert(sys_days{ 2000y/ 6/ 0} == sys_days{days{ 11108}}); + static_assert(sys_days{ 2000y/ 6/255} == sys_days{days{ 11363}}); + static_assert(sys_days{ 2000y/ 7/ 0} == sys_days{days{ 11138}}); + static_assert(sys_days{ 2000y/ 7/255} == sys_days{days{ 11393}}); + static_assert(sys_days{ 2000y/ 8/ 0} == sys_days{days{ 11169}}); + static_assert(sys_days{ 2000y/ 8/255} == sys_days{days{ 11424}}); + static_assert(sys_days{ 2000y/ 9/ 0} == sys_days{days{ 11200}}); + static_assert(sys_days{ 2000y/ 9/255} == sys_days{days{ 11455}}); + static_assert(sys_days{ 2000y/10/ 0} == sys_days{days{ 11230}}); + static_assert(sys_days{ 2000y/10/255} == sys_days{days{ 11485}}); + static_assert(sys_days{ 2000y/11/ 0} == sys_days{days{ 11261}}); + static_assert(sys_days{ 2000y/11/255} == sys_days{days{ 11516}}); + static_assert(sys_days{ 2000y/12/ 0} == sys_days{days{ 11291}}); + static_assert(sys_days{ 2000y/12/255} == sys_days{days{ 11546}}); + static_assert(sys_days{ -400y/ 2/255} == sys_days{days{ -865340}}); + static_assert(sys_days{ -400y/ 3/ 0} == sys_days{days{ -865566}}); + static_assert(sys_days{ -1y/ 2/255} == sys_days{days{ -719608}}); + static_assert(sys_days{ -1y/ 3/ 0} == sys_days{days{ -719835}}); + static_assert(sys_days{ -1y/12/255} == sys_days{days{ -719305}}); + static_assert(sys_days{ 0y/ 1/ 0} == sys_days{days{ -719529}}); + static_assert(sys_days{ 0y/ 2/255} == sys_days{days{ -719243}}); + static_assert(sys_days{ 0y/ 3/ 0} == sys_days{days{ -719469}}); + static_assert(sys_days{ 1900y/ 3/ 0} == sys_days{days{ -25509}}); + static_assert(sys_days{ 1901y/ 2/255} == sys_days{days{ -24917}}); + static_assert(sys_days{ 1903y/ 3/ 0} == sys_days{days{ -24414}}); + static_assert(sys_days{ 1904y/ 2/255} == sys_days{days{ -23822}}); + static_assert(sys_days{ 1996y/ 3/ 0} == sys_days{days{ 9555}}); + static_assert(sys_days{ 1997y/ 2/255} == sys_days{days{ 10147}}); + static_assert(sys_days{ 1999y/ 3/ 0} == sys_days{days{ 10650}}); + static_assert(sys_days{ 2000y/ 2/255} == sys_days{days{ 11242}}); + static_assert(sys_days{ 2000y/ 3/ 0} == sys_days{days{ 11016}}); + static_assert(sys_days{ 2001y/ 2/255} == sys_days{days{ 11608}}); + static_assert(sys_days{ 2003y/ 3/ 0} == sys_days{days{ 12111}}); + static_assert(sys_days{ 2004y/ 2/255} == sys_days{days{ 12703}}); + static_assert(sys_days{ 2096y/ 3/ 0} == sys_days{days{ 46080}}); + static_assert(sys_days{ 2097y/ 2/255} == sys_days{days{ 46672}}); + static_assert(sys_days{ 2099y/ 3/ 0} == sys_days{days{ 47175}}); + static_assert(sys_days{ 2100y/ 2/255} == sys_days{days{ 47767}}); + static_assert(sys_days{-32767y/ 1/ 0} == sys_days{days{-12687429}}); + static_assert(sys_days{ 32767y/12/255} == sys_days{days{ 11248961}}); + // clang-format on + } else { + sys_days sys2{year{y_min} / 1 / 1}; + + for (int iy = y_min; iy <= y_max; ++iy) { + const year y{iy}; + + for (auto um = 1u; um <= 12u; ++um) { + const month m{um}; + + const year_month_day ymd_first = y / m / 1; + assert(sys_days{ymd_first} == sys2); + assert(year_month_day{sys2} == ymd_first); + + const year_month_day ymd_min = y / m / 0; + assert(sys_days{ymd_min} == sys2 - days{1}); + + const year_month_day ymd_max = y / m / 255; + assert(sys_days{ymd_max} == sys2 + days{254}); + + const year_month_day ymd_last = y / m / last; + sys2 += (ymd_last.day() - 1d); + assert(sys_days{ymd_last} == sys2); + assert(year_month_day{sys2} == ymd_last); + + sys2 += days{1}; + } + } + } } constexpr void year_month_day_last_test() {