Skip to content
Merged
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
90 changes: 84 additions & 6 deletions stl/inc/chrono
Original file line number Diff line number Diff line change
Expand Up @@ -5537,6 +5537,8 @@ namespace chrono {
_Hours = _Val.hours().count();
_Minutes = _Val.minutes().count();
_Seconds = static_cast<int>(_Val.seconds().count());
} else if constexpr (_Is_any_of_v<_Ty, sys_info, local_info>) {
return {}; // none of the valid conversion specifiers need tm fields
} else if constexpr (_Is_specialization_v<_Ty, time_point>) {
const auto _Dp = _CHRONO floor<days>(_Val);
const year_month_day _Ymd{_Dp};
Expand Down Expand Up @@ -5655,6 +5657,47 @@ namespace chrono {
return _Os << _STD format(_Os.getloc(), _STATICALLY_WIDEN(_CharT, "{:%T}"), _Val);
}

#pragma warning(push)
#pragma warning(disable : 4365) // 'argument': conversion from 'char' to 'const wchar_t', signed/unsigned mismatch
template <class _CharT>
_NODISCARD decltype(auto) _Widen_string(const string& _Str) {
if constexpr (is_same_v<_CharT, char>) {
return _Str;
} else {
return wstring{_Str.begin(), _Str.end()}; // TRANSITION, should probably use ctype::widen
}
}
#pragma warning(pop)

template <class _CharT, class _Traits>
basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const sys_info& _Val) {
return _Os << _STD format(_Os.getloc(),
_STATICALLY_WIDEN(_CharT, "begin: {}, end: {}, offset: {}, save: {}, abbrev: {}"), //
_Val.begin, _Val.end, _Val.offset, _Val.save, _Widen_string<_CharT>(_Val.abbrev));
}

template <class _CharT, class _Traits>
basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const local_info& _Val) {
switch (_Val.result) {
case local_info::unique:
return _Os << _STD format(_Os.getloc(), //
_STATICALLY_WIDEN(_CharT, "result: unique, first: ({})"), //
_Val.first);
case local_info::nonexistent:
return _Os << _STD format(_Os.getloc(),
_STATICALLY_WIDEN(_CharT, "result: nonexistent, first: ({}), second: ({})"), //
_Val.first, _Val.second);
case local_info::ambiguous:
return _Os << _STD format(_Os.getloc(),
_STATICALLY_WIDEN(_CharT, "result: ambiguous, first: ({}), second: ({})"), //
_Val.first, _Val.second);
default:
return _Os << _STD format(_Os.getloc(), //
_STATICALLY_WIDEN(_CharT, "result: {}, first: ({}), second: ({})"), //
_Val.result, _Val.first, _Val.second);
}
}

template <class _CharT, class _Traits, class _Duration>
// clang-format off
requires (!treat_as_floating_point_v<typename _Duration::rep> && _Duration{1} < days{1})
Expand Down Expand Up @@ -5815,6 +5858,8 @@ namespace chrono {
} else if constexpr (_Is_specialization_v<_Ty, hh_mm_ss>) {
return _Type == 'H' || _Type == 'I' || _Type == 'M' || _Type == 'S' || _Type == 'r' || _Type == 'R'
|| _Type == 'T' || _Type == 'p';
} else if constexpr (_Is_any_of_v<_Ty, sys_info, local_info>) {
return _Type == 'z' || _Type == 'Z';
} else if constexpr (_Is_specialization_v<_Ty, time_point>) {
if constexpr (!is_same_v<typename _Ty::clock, local_t>) {
if (_Type == 'z' || _Type == 'Z') {
Expand Down Expand Up @@ -5889,6 +5934,12 @@ namespace chrono {
template <class _Ty>
bool _Custom_write(
basic_ostream<_CharT>& _Os, const _Chrono_spec<_CharT>& _Spec, const tm& _Time, const _Ty& _Val) {
if constexpr (is_same_v<_Ty, local_info>) {
if (_Val.result != local_info::unique) {
_THROW(format_error("Cannot print non-unique local_info"));
}
}

const auto _Year = _Time.tm_year + 1900;
const auto _Month = _Time.tm_mon + 1;
const bool _Has_modifier = _Spec._Modifier != '\0';
Expand Down Expand Up @@ -5996,15 +6047,34 @@ namespace chrono {
_Write_seconds(_Os, _Val);
return true;
case 'Z':
_Os << _Time_zone_abbreviation;
if constexpr (is_same_v<_Ty, sys_info>) {
_Os << _Widen_string<_CharT>(_Val.abbrev);
} else if constexpr (is_same_v<_Ty, local_info>) {
_Os << _Widen_string<_CharT>(_Val.first.abbrev);
} else {
_Os << _Time_zone_abbreviation;
}
return true;
case 'z':
_Os << _STATICALLY_WIDEN(_CharT, "+00");
if (_Has_modifier) {
_Os << _CharT{':'};
{
hh_mm_ss<seconds> _Offset;

if constexpr (is_same_v<_Ty, sys_info>) {
_Offset = hh_mm_ss<seconds>{_Val.offset};
} else if constexpr (is_same_v<_Ty, local_info>) {
_Offset = hh_mm_ss<seconds>{_Val.first.offset};
} else {
_Offset = hh_mm_ss<seconds>{};
}

const auto _Sign = _Offset.is_negative() ? _CharT{'-'} : _CharT{'+'};
const auto _Separator =
_Has_modifier ? _STATICALLY_WIDEN(_CharT, ":") : _STATICALLY_WIDEN(_CharT, "");

_Os << _STD format(_STATICALLY_WIDEN(_CharT, "{}{:02}{}{:02}"), _Sign, _Offset.hours().count(),
_Separator, _Offset.minutes().count());
return true;
}
_Os << _STATICALLY_WIDEN(_CharT, "00");
return true;
default:
return false;
}
Expand Down Expand Up @@ -6099,6 +6169,14 @@ template <class _Rep, class _Period, class _CharT>
struct formatter<_CHRONO hh_mm_ss<_CHRONO duration<_Rep, _Period>>, _CharT>
: _Fill_tm_formatter<_CHRONO hh_mm_ss<_CHRONO duration<_Rep, _Period>>, _CharT> {};

template <class _CharT>
struct formatter<_CHRONO sys_info, _CharT> //
: _Fill_tm_formatter<_CHRONO sys_info, _CharT> {};

template <class _CharT>
struct formatter<_CHRONO local_info, _CharT> //
: _Fill_tm_formatter<_CHRONO local_info, _CharT> {};

template <class _Duration, class _CharT>
struct formatter<_CHRONO sys_time<_Duration>, _CharT> {
auto parse(basic_format_parse_context<_CharT>& _Parse_ctx) {
Expand Down
15 changes: 8 additions & 7 deletions stl/inc/yvals_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,6 @@
// P0325R4 to_array()
// P0339R6 polymorphic_allocator<>
// P0355R7 <chrono> Calendars And Time Zones
// (partially implemented)
// P0356R5 bind_front()
// P0357R3 Supporting Incomplete Types In reference_wrapper
// P0408R7 Efficient Access To basic_stringbuf's Buffer
Expand Down Expand Up @@ -1172,12 +1171,6 @@
#define __cpp_lib_variant 201606L
#endif // _HAS_CXX17

#if _HAS_CXX17
#define __cpp_lib_chrono 201611L // P0505R0 constexpr For <chrono> (Again)
#else // _HAS_CXX17
#define __cpp_lib_chrono 201510L // P0092R1 <chrono> floor(), ceil(), round(), abs()
#endif // _HAS_CXX17

// C++20
#define __cpp_lib_atomic_value_initialization 201911L

Expand Down Expand Up @@ -1303,6 +1296,14 @@
#define __cpp_lib_array_constexpr 201803L
#endif // _HAS_CXX17

#if _HAS_CXX20 && defined(__cpp_lib_concepts) // TRANSITION, GH-395
#define __cpp_lib_chrono 201907L // P1466R3 Miscellaneous Minor Fixes For <chrono>
#elif _HAS_CXX17
#define __cpp_lib_chrono 201611L // P0505R0 constexpr For <chrono> (Again)
#else // _HAS_CXX17
#define __cpp_lib_chrono 201510L // P0092R1 <chrono> floor(), ceil(), round(), abs()
#endif // _HAS_CXX17

#if _HAS_CXX20
#define __cpp_lib_shared_ptr_arrays 201707L // P0674R1 make_shared() For Arrays
#else // _HAS_CXX20
Expand Down
3 changes: 3 additions & 0 deletions tests/libcxx/expected_results.txt
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,9 @@ std/language.support/support.limits/support.limits.general/algorithm.version.pas
std/language.support/support.limits/support.limits.general/functional.version.pass.cpp FAIL
std/language.support/support.limits/support.limits.general/iterator.version.pass.cpp FAIL

# Test expects __cpp_lib_chrono to have the old value 201611L for P0505R0; we define the C++20 value 201907L for P1466R3.
std/language.support/support.limits/support.limits.general/chrono.version.pass.cpp FAIL

# We unconditionally define __cpp_lib_addressof_constexpr; test error says it
# "should not be defined when TEST_HAS_BUILTIN(__builtin_addressof) || TEST_GCC_VER >= 700 is not defined!"
std/language.support/support.limits/support.limits.general/memory.version.pass.cpp FAIL
Expand Down
3 changes: 3 additions & 0 deletions tests/libcxx/skipped_tests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,9 @@ language.support\support.limits\support.limits.general\algorithm.version.pass.cp
language.support\support.limits\support.limits.general\functional.version.pass.cpp
language.support\support.limits\support.limits.general\iterator.version.pass.cpp

# Test expects __cpp_lib_chrono to have the old value 201611L for P0505R0; we define the C++20 value 201907L for P1466R3.
language.support\support.limits\support.limits.general\chrono.version.pass.cpp

# We unconditionally define __cpp_lib_addressof_constexpr; test error says it
# "should not be defined when TEST_HAS_BUILTIN(__builtin_addressof) || TEST_GCC_VER >= 700 is not defined!"
language.support\support.limits\support.limits.general\memory.version.pass.cpp
Expand Down
110 changes: 108 additions & 2 deletions tests/std/tests/P0355R7_calendars_and_time_zones_formatting/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include <type_traits>
#include <utility>

#include <timezone_data.hpp>

using namespace std;
using namespace chrono;

Expand Down Expand Up @@ -212,9 +214,9 @@ void empty_braces_helper(const Arg& val, const CharT* const expected) {
template <class Str>
constexpr void print(Str str) {
if constexpr (is_same_v<Str, string>) {
cout << "res: " << str << "\n";
cout << str << "\n";
} else {
wcout << "res: " << str << "\n";
wcout << str << "\n";
}
}

Expand Down Expand Up @@ -611,6 +613,107 @@ void test_exception_classes() {
}
}

template <typename CharT>
void test_information_classes() {
const tzdb& database = get_tzdb();

const time_zone* const sydney_tz = database.locate_zone(Sydney::Tz_name);
assert(sydney_tz != nullptr);

const time_zone* const la_tz = database.locate_zone(LA::Tz_name);
assert(la_tz != nullptr);

const sys_info sys1 = sydney_tz->get_info(Sydney::Std_1.begin() + days{1});
const sys_info sys2 = sydney_tz->get_info(Sydney::Day_2.begin() + days{1});
const sys_info sys3 = la_tz->get_info(LA::Std_1.begin() + days{1});
const sys_info sys4 = la_tz->get_info(LA::Day_2.begin() + days{1});

const local_info loc1 = sydney_tz->get_info(Sydney::Std_1.local_begin() + days{1});
const local_info loc2 = sydney_tz->get_info(Sydney::Day_2.local_begin() + days{1});
const local_info loc3 = la_tz->get_info(LA::Std_1.local_begin() + days{1});
const local_info loc4 = la_tz->get_info(LA::Day_2.local_begin() + days{1});

const local_info ambiguous1 = sydney_tz->get_info(Sydney::Std_1.local_begin());
const local_info ambiguous2 = la_tz->get_info(LA::Std_1.local_begin());

const local_info nonexistent1 = sydney_tz->get_info(Sydney::Std_1.local_end());
const local_info nonexistent2 = la_tz->get_info(LA::Std_1.local_end());

empty_braces_helper(sys1, STR("begin: 2020-04-04 16:00:00, end: 2020-10-03 16:00:00, "
"offset: 36000s, save: 0min, abbrev: GMT+10"));
empty_braces_helper(sys2, STR("begin: 2020-10-03 16:00:00, end: 2021-04-03 16:00:00, "
"offset: 39600s, save: 60min, abbrev: GMT+11"));
empty_braces_helper(sys3, STR("begin: 2020-11-01 09:00:00, end: 2021-03-14 10:00:00, "
"offset: -28800s, save: 0min, abbrev: PST"));
empty_braces_helper(sys4, STR("begin: 2021-03-14 10:00:00, end: 2021-11-07 09:00:00, "
"offset: -25200s, save: 60min, abbrev: PDT"));
empty_braces_helper(loc1, STR("result: unique, "
"first: (begin: 2020-04-04 16:00:00, end: 2020-10-03 16:00:00, "
"offset: 36000s, save: 0min, abbrev: GMT+10)"));
empty_braces_helper(loc2, STR("result: unique, "
"first: (begin: 2020-10-03 16:00:00, end: 2021-04-03 16:00:00, "
"offset: 39600s, save: 60min, abbrev: GMT+11)"));
empty_braces_helper(loc3, STR("result: unique, "
"first: (begin: 2020-11-01 09:00:00, end: 2021-03-14 10:00:00, "
"offset: -28800s, save: 0min, abbrev: PST)"));
empty_braces_helper(loc4, STR("result: unique, "
"first: (begin: 2021-03-14 10:00:00, end: 2021-11-07 09:00:00, "
"offset: -25200s, save: 60min, abbrev: PDT)"));
empty_braces_helper(ambiguous1, STR("result: ambiguous, "
"first: (begin: 2019-10-05 16:00:00, end: 2020-04-04 16:00:00, "
"offset: 39600s, save: 60min, abbrev: GMT+11), "
"second: (begin: 2020-04-04 16:00:00, end: 2020-10-03 16:00:00, "
"offset: 36000s, save: 0min, abbrev: GMT+10)"));
empty_braces_helper(ambiguous2, STR("result: ambiguous, "
"first: (begin: 2020-03-08 10:00:00, end: 2020-11-01 09:00:00, "
"offset: -25200s, save: 60min, abbrev: PDT), "
"second: (begin: 2020-11-01 09:00:00, end: 2021-03-14 10:00:00, "
"offset: -28800s, save: 0min, abbrev: PST)"));
empty_braces_helper(nonexistent1, STR("result: nonexistent, "
"first: (begin: 2020-04-04 16:00:00, end: 2020-10-03 16:00:00, "
"offset: 36000s, save: 0min, abbrev: GMT+10), "
"second: (begin: 2020-10-03 16:00:00, end: 2021-04-03 16:00:00, "
"offset: 39600s, save: 60min, abbrev: GMT+11)"));
empty_braces_helper(nonexistent2, STR("result: nonexistent, "
"first: (begin: 2020-11-01 09:00:00, end: 2021-03-14 10:00:00, "
"offset: -28800s, save: 0min, abbrev: PST), "
"second: (begin: 2021-03-14 10:00:00, end: 2021-11-07 09:00:00, "
"offset: -25200s, save: 60min, abbrev: PDT)"));

assert(format(STR("{:%z %Ez %Oz %Z}"), sys1) == STR("+1000 +10:00 +10:00 GMT+10"));
assert(format(STR("{:%z %Ez %Oz %Z}"), sys2) == STR("+1100 +11:00 +11:00 GMT+11"));
assert(format(STR("{:%z %Ez %Oz %Z}"), sys3) == STR("-0800 -08:00 -08:00 PST"));
assert(format(STR("{:%z %Ez %Oz %Z}"), sys4) == STR("-0700 -07:00 -07:00 PDT"));

assert(format(STR("{:%z %Ez %Oz %Z}"), loc1) == STR("+1000 +10:00 +10:00 GMT+10"));
assert(format(STR("{:%z %Ez %Oz %Z}"), loc2) == STR("+1100 +11:00 +11:00 GMT+11"));
assert(format(STR("{:%z %Ez %Oz %Z}"), loc3) == STR("-0800 -08:00 -08:00 PST"));
assert(format(STR("{:%z %Ez %Oz %Z}"), loc4) == STR("-0700 -07:00 -07:00 PDT"));

throw_helper(STR("{:%z}"), ambiguous1);
throw_helper(STR("{:%z}"), ambiguous2);
throw_helper(STR("{:%z}"), nonexistent1);
throw_helper(STR("{:%z}"), nonexistent2);

throw_helper(STR("{:%Z}"), ambiguous1);
throw_helper(STR("{:%Z}"), ambiguous2);
throw_helper(STR("{:%Z}"), nonexistent1);
throw_helper(STR("{:%Z}"), nonexistent2);

// Additionally test zero and half-hour offsets.
const time_zone* const utc_tz = database.locate_zone("Etc/UTC"sv);
assert(utc_tz != nullptr);

const time_zone* const kolkata_tz = database.locate_zone("Asia/Kolkata"sv);
assert(kolkata_tz != nullptr);

const sys_info sys5 = utc_tz->get_info(sys_days{2021y / January / 1});
const sys_info sys6 = kolkata_tz->get_info(sys_days{2021y / January / 1});

assert(format(STR("{:%z %Ez %Oz}"), sys5) == STR("+0000 +00:00 +00:00"));
assert(format(STR("{:%z %Ez %Oz}"), sys6) == STR("+0530 +05:30 +05:30"));
}

int main() {
test_parse_conversion_spec<char>();
test_parse_conversion_spec<wchar_t>();
Expand Down Expand Up @@ -673,4 +776,7 @@ int main() {
test_hh_mm_ss_formatter<wchar_t>();

test_exception_classes();

test_information_classes<char>();
test_information_classes<wchar_t>();
}
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,12 @@ STATIC_ASSERT(__cpp_lib_char8_t == 201907L);

#ifndef __cpp_lib_chrono
#error __cpp_lib_chrono is not defined
#elif _HAS_CXX20 && defined(__cpp_lib_concepts) // TRANSITION, GH-395
#if __cpp_lib_chrono != 201907L
#error __cpp_lib_chrono is not 201907L
#else
STATIC_ASSERT(__cpp_lib_chrono == 201907L);
#endif
#elif _HAS_CXX17
#if __cpp_lib_chrono != 201611L
#error __cpp_lib_chrono is not 201611L
Expand Down