Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 23 additions & 11 deletions stl/inc/chrono
Original file line number Diff line number Diff line change
Expand Up @@ -3211,11 +3211,23 @@ namespace chrono {
}

_NODISCARD static pair<int, int> _Decompose_year(const int _Year) {
int _Two_d_year = _Year % 100;
if (_Two_d_year < 0) {
_Two_d_year += 100;
// LWG-3831: the two-digit year is taken without regard to the sign of the whole year number.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No change requested: We don't usually cite resolved LWG issues, but this is clear enough.

pair<int, int> _Result(_Year, _Year % 100);
_Result.first -= _Result.second;
if (_Result.second < 0) {
_Result.first -= 100;
_Result.second = -_Result.second;
}

return _Result;
}

_NODISCARD static int _Compose_year(const int _Century, const int _Two_d_year) {
if (_Century >= 0 || _Two_d_year == 0) {
return _Century + _Two_d_year;
} else {
return _Century + (100 - _Two_d_year);
}
return {_Year - _Two_d_year, _Two_d_year};
}

_NODISCARD bool _Update_if_valid(const tm& _Tp, const bool _Full_year) {
Expand Down Expand Up @@ -3354,7 +3366,7 @@ namespace chrono {
bool _Have_year = false;
int _Year{0};
if (_Two_dig_year) {
_Year = *_Century + *_Two_dig_year;
_Year = _Compose_year(*_Century, *_Two_dig_year);
_Have_year = true;
if (_Day_of_year) {
_No_err = _No_err && _Yday_to_month_day(*_Day_of_year, _Year);
Expand Down Expand Up @@ -3450,7 +3462,7 @@ namespace chrono {
// %C is only combined with %g if %G is missing, to avoid an unnecessary parse failure when the ISO and
// Gregorian years are in different centuries.
if (_Two_dig_iso_year && _Century && !_Iso_year) {
_No_err = _No_err && _Update(_Iso_year, *_Century + *_Two_dig_iso_year);
_No_err = _No_err && _Update(_Iso_year, _Compose_year(*_Century, *_Two_dig_iso_year));
}

return _No_err;
Expand Down Expand Up @@ -3588,7 +3600,7 @@ namespace chrono {

if constexpr (_Can_rep_day) {
if (_For_time_point) {
const year_month_day _Ymd{year{*_Century + *_Two_dig_year},
const year_month_day _Ymd{year{_Compose_year(*_Century, *_Two_dig_year)},
month{static_cast<unsigned int>(*_Month)}, day{static_cast<unsigned int>(*_Day)}};
_Result += _CHRONO duration_cast<_DurationType>(static_cast<sys_days>(_Ymd).time_since_epoch());
} else if (_Used & _F_doy) {
Expand Down Expand Up @@ -3724,7 +3736,7 @@ namespace chrono {

_NODISCARD bool _Make_year(year& _Year_result) {
if (_Calculate_year_fields() && _Used_fields() == _F_year) {
_Year_result = year{*_Century + *_Two_dig_year};
_Year_result = year{_Compose_year(*_Century, *_Two_dig_year)};
return true;
} else {
return false;
Expand All @@ -3733,8 +3745,8 @@ namespace chrono {

_NODISCARD bool _Make_year_month(year_month& _Year_month_result) {
if (_Calculate_year_fields() && _Used_fields() == (_F_mon | _F_year)) {
_Year_month_result =
year_month{year{*_Century + *_Two_dig_year}, month{static_cast<unsigned int>(*_Month)}};
_Year_month_result = year_month{
year{_Compose_year(*_Century, *_Two_dig_year)}, month{static_cast<unsigned int>(*_Month)}};
return true;
} else {
return false;
Expand All @@ -3752,7 +3764,7 @@ namespace chrono {
}

if (_Consistent && _Test_bits(_Used_fields(), _Required, _Optional)) {
_Year_month_day_result = year_month_day{year{*_Century + *_Two_dig_year},
_Year_month_day_result = year_month_day{year{_Compose_year(*_Century, *_Two_dig_year)},
month{static_cast<unsigned int>(*_Month)}, day{static_cast<unsigned int>(*_Day)}};
return true;
} else {
Expand Down
1 change: 0 additions & 1 deletion tests/libcxx/expected_results.txt
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,6 @@ std/language.support/cmp/cmp.alg/weak_order.pass.cpp FAIL
# This test also has a bogus assumption about the file_time epoch, and file_time<nanoseconds> is doomed on Windows.
std/time/time.clock/time.clock.file/ostream.pass.cpp FAIL

# GH-4248: <chrono>: format() %y mishandles negative year values
# LLVM-74727: [libc++] Should formatting year{-99} with %C produce "-1" or "-01"?
std/time/time.syn/formatter.year.pass.cpp:2 FAIL

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -470,14 +470,17 @@ void test_year_formatter() {
empty_braces_helper(year{121}, STR("0121"));

assert(format(STR("{:%Y %y%C}"), year{1912}) == STR("1912 1219"));
assert(format(STR("{:%Y %y%C}"), year{-1912}) == STR("-1912 88-20"));
assert(format(STR("{:%Y %y%C}"), year{-1912}) == STR("-1912 12-20"));
assert(format(STR("{:%Y %y%C}"), year{-200}) == STR("-0200 00-02"));
assert(format(STR("{:%Y %y%C}"), year{200}) == STR("0200 0002"));
// TRANSITION, add tests for EY Oy Ey EC

empty_braces_helper(year{1900}, STR("1900"));
empty_braces_helper(year{2000}, STR("2000"));
empty_braces_helper(year{-32768}, STR("-32768 is not a valid year"));

// [time.format] example
assert(format(STR("{:%C %y}"), year{-1976}) == STR("-20 76"));
}

template <typename CharT>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -541,8 +541,14 @@ void parse_calendar_types_basic() {
assert(y == 1999y);

// negative century
test_parse("-1 5", "%C %y", y);
test_parse("-1 95", "%C %y", y);
assert(y == -95y);
test_parse("-2 00", "%C %y", y);
assert(y == -200y);

// [time.parse] example
test_parse("-20 76", "%3C %y", y);
assert(y == -1976y);

// check consistency, or lack thereof
test_parse("1887 18 87", "%Y %C %y", y);
Expand Down