From 01614b40228b416fffa620e3fffe1376dec089ab Mon Sep 17 00:00:00 2001 From: Gaspard Petit Date: Fri, 24 Feb 2023 22:54:57 -0500 Subject: [PATCH] Increase the precision when converting milliseconds to years With the current implementation, a large negative millisecond timestamp will result in a relatively normal positive year (int64::min translates into 1535). This change improves the precision for large number of days obtained from large millisecond values. --- include/date/date.h | 14 +++++++------- test/date_test/day.pass.cpp | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/include/date/date.h b/include/date/date.h index 6960e8cd..e8d02dbe 100644 --- a/include/date/date.h +++ b/include/date/date.h @@ -174,7 +174,7 @@ using ratio_divide = decltype(std::ratio_divide{}); // durations using days = std::chrono::duration - , std::chrono::hours::period>>; + , std::chrono::hours::period>>; using weeks = std::chrono::duration , days::period>>; @@ -394,7 +394,7 @@ operator<<(std::basic_ostream& os, const month& m); class year { - short y_; + int y_; public: year() = default; @@ -464,7 +464,7 @@ class weekday CONSTCD11 weekday_last operator[](last_spec) const NOEXCEPT; private: - static CONSTCD14 unsigned char weekday_from_days(int z) NOEXCEPT; + static CONSTCD14 unsigned char weekday_from_days(int64_t z) NOEXCEPT; friend CONSTCD11 bool operator==(const weekday& x, const weekday& y) NOEXCEPT; friend CONSTCD14 days operator-(const weekday& x, const weekday& y) NOEXCEPT; @@ -1478,7 +1478,7 @@ inline days operator-(const day& x, const day& y) NOEXCEPT { - return days{static_cast(static_cast(x) + return days{static_cast(static_cast(x) - static_cast(y))}; } @@ -1820,9 +1820,9 @@ operator<<(std::basic_ostream& os, const year& y) CONSTCD14 inline unsigned char -weekday::weekday_from_days(int z) NOEXCEPT +weekday::weekday_from_days(int64_t z) NOEXCEPT { - auto u = static_cast(z); + auto u = static_cast(z); return static_cast(z >= -4 ? (u+4) % 7 : u % 7); } @@ -3099,7 +3099,7 @@ year_month_day::from_days(days dp) NOEXCEPT auto const mp = (5*doy + 2)/153; // [0, 11] auto const d = doy - (153*mp+2)/5 + 1; // [1, 31] auto const m = mp < 10 ? mp+3 : mp-9; // [1, 12] - return year_month_day{date::year{y + (m <= 2)}, date::month(m), date::day(d)}; + return year_month_day{date::year{static_cast(y + (m <= 2))}, date::month(m), date::day(d)}; } template diff --git a/test/date_test/day.pass.cpp b/test/date_test/day.pass.cpp index 0dbdf688..f62c7025 100644 --- a/test/date_test/day.pass.cpp +++ b/test/date_test/day.pass.cpp @@ -140,4 +140,20 @@ main() os.str(""); os << d; assert(os.str() == "12"); + + { + ::date::sys_time timePoint{ std::chrono::milliseconds(0) }; + std::chrono::time_point dayPoint = ::date::floor<::date::days>(timePoint); + ::date::fields dateFields{ ::date::year_month_day{ dayPoint }, ::date::time_of_day{ timePoint - dayPoint } }; + int year = (int16_t)static_cast(dateFields.ymd.year()); + assert(year == 1970); + } + + { + ::date::sys_time timePoint{ std::chrono::milliseconds(std::numeric_limits::min()) }; + std::chrono::time_point dayPoint = ::date::floor<::date::days>(timePoint); + ::date::fields dateFields{ ::date::year_month_day{ dayPoint }, ::date::time_of_day{ timePoint - dayPoint } }; + int year = static_cast(dateFields.ymd.year()); + assert(year == -292275055); + } }