Skip to content
Open
20 changes: 14 additions & 6 deletions stl/inc/chrono
Original file line number Diff line number Diff line change
Expand Up @@ -1634,18 +1634,18 @@ namespace chrono {
constexpr hh_mm_ss() noexcept : hh_mm_ss{_Duration::zero()} {}
constexpr explicit hh_mm_ss(_Duration _Dur)
: _Is_neg{_Dur < _Duration::zero()},
_Hours{_CHRONO _Duration_cast_underflow_to_zero<_CHRONO hours>(_CHRONO abs(_Dur))},
_Hours{_CHRONO _Duration_cast_underflow_to_zero<_CHRONO hours>(_ABS_D(_Dur, _Is_neg))},
_Mins{_CHRONO _Duration_cast_underflow_to_zero<_CHRONO minutes>(
_CHRONO _Remove_duration_part<_CHRONO hours>(_CHRONO abs(_Dur)))},
_CHRONO _Remove_duration_part<_CHRONO hours>(_ABS_D(_Dur, _Is_neg)))},
_Secs{_CHRONO _Duration_cast_underflow_to_zero<_CHRONO seconds>(
_CHRONO _Remove_duration_part<_CHRONO minutes>(
_CHRONO _Remove_duration_part<_CHRONO hours>(_CHRONO abs(_Dur))))} {
_CHRONO _Remove_duration_part<_CHRONO hours>(_ABS_D(_Dur, _Is_neg))))} {
if constexpr (treat_as_floating_point_v<typename precision::rep>) {
// no need to deal with underflow here, because floating durations allow it
_Sub_secs = _CHRONO abs(_Dur) - hours() - minutes() - seconds();
_Sub_secs = _ABS_D(_Dur, _Is_neg) - hours() - minutes() - seconds();
} else {
_Sub_secs =
_CHRONO duration_cast<precision>(_CHRONO _Remove_duration_part<_CHRONO seconds>(_CHRONO abs(_Dur)));
_Sub_secs = _CHRONO duration_cast<precision>(
_CHRONO _Remove_duration_part<_CHRONO seconds>(_ABS_D(_Dur, _Is_neg)));
}
}

Expand Down Expand Up @@ -1674,6 +1674,14 @@ namespace chrono {
}

private:
_NODISCARD constexpr static _Duration _ABS_D(_Duration _Dur, bool _Is_neg) {
if constexpr (is_unsigned_v<typename _Duration::rep>) {
return _Dur;
} else {
return _Is_neg ? -_Dur : _Dur;
}
}

bool _Is_neg;
_CHRONO hours _Hours;
_CHRONO minutes _Mins;
Expand Down
14 changes: 14 additions & 0 deletions tests/std/tests/P0355R7_calendars_and_time_zones_hms/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#include <ratio>
#include <type_traits>

// Extended to test LWG-4274 "The chrono::hh_mm_ss constructor is ill-formed for unsigned durations"

using namespace std;
using namespace std::chrono;

Expand Down Expand Up @@ -105,6 +107,17 @@ constexpr void constructor() {
assert(f_hms_hours{}.subseconds() == f_hms_hours{hours::zero()}.subseconds());
}

// Test LWG-4274 "The chrono::hh_mm_ss constructor is ill-formed for unsigned durations"
constexpr void constructor_unsigned_durations() {
duration<unsigned long long, milli> unsigned_duration{37 + 1000 * (7 + 4 * 60 + 3 * 3600)};
hh_mm_ss a{unsigned_duration};
assert(!a.is_negative());
assert(a.hours() == 3h);
assert(a.minutes() == 4min);
assert(a.seconds() == 7s);
assert(a.subseconds() == 37ms);
}

constexpr void is_negative() {
static_assert(noexcept(hms_hours{}.is_negative()));
static_assert(noexcept(f_hms_hours{}.is_negative()));
Expand Down Expand Up @@ -210,6 +223,7 @@ constexpr bool test() {
make12_24();
fractional_width();
constructor();
constructor_unsigned_durations();
is_negative();
hour();
mins();
Expand Down