diff --git a/stl/inc/chrono b/stl/inc/chrono index 502f75a2ffa..dbf2c37a6c3 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -5612,7 +5612,11 @@ namespace chrono { return true; case 'Q': if constexpr (_Is_specialization_v<_Ty, duration>) { - _Os << _STD abs(_Val.count()); + if constexpr (is_unsigned_v) { + _Os << _Val.count(); + } else { + _Os << _STD abs(_Val.count()); + } } else { _STL_INTERNAL_CHECK(false); } diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_formatting/test.cpp b/tests/std/tests/P0355R7_calendars_and_time_zones_formatting/test.cpp index 26c4fc14db4..014b72f9477 100644 --- a/tests/std/tests/P0355R7_calendars_and_time_zones_formatting/test.cpp +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_formatting/test.cpp @@ -21,6 +21,7 @@ #include // Extended to test LWG-4257 "Stream insertion for chrono::local_time should be constrained" +// Extended to test GH-5945 ": cannot format unsigned durations" using namespace std; using namespace chrono; @@ -286,6 +287,11 @@ void test_duration_formatter() { assert(format(STR("{:%T %j}"), duration{1.55f}) == STR("37:11:59 1")); assert(format(STR("{:%T %j}"), duration{-1.55f}) == STR("-37:11:59 1")); + // GH-5945 ": cannot format unsigned durations" + assert(format(STR("{:%T %j %q %Q}"), duration{4} + 30min) + == STR("96:30:00 4 min 5790")); + assert(format(STR("{:%T %j}"), duration{4} + 23h + 30min) == STR("119:30:00 4")); + // GH-4247: : format() should accept %X and %EX for duration and hh_mm_ss assert(format(STR("{:%X}"), 9h + 7min + 5s) == STR("09:07:05")); assert(format(STR("{:%EX}"), 9h + 7min + 5s) == STR("09:07:05")); @@ -1102,8 +1108,29 @@ void check_stream_insertion_operator() { check_stream_insertion_operator_for_duration(); } +// Test introduced for GH-5945 ": cannot format unsigned durations" +void test_format_duration_with_unsigned_rep() { + // operator<<(ostream&, duration _Dur) only prints _Dur.count() (does not use abs) + { + ostringstream oss; + oss << duration{3}; + assert(oss.str() == "3ns"); + } + { + ostringstream oss; + oss << duration{-3}; + assert(oss.str() == "-3ns"); + } + + // format calls abs under the hood when needed, this would be rejected before fix. + assert(format("{}", duration{-3}) == "-3ns"); + assert(format("{}", duration{3}) == "3ns"); + assert(format("{:%Q}", duration{3}) == "3"); +} + void test() { test_unsigned_sys_time_format_after_LWG_4274(); + test_format_duration_with_unsigned_rep(); check_stream_insertion_operator();