libstdc++: Add std::format support to <chrono>
This adds the operator<< overloads and std::formatter specializations required by C++20 so that <chrono> types can be written to ostreams and printed with std::format. libstdc++-v3/ChangeLog: * include/Makefile.am: Add new header. * include/Makefile.in: Regenerate. * include/std/chrono (operator<<): Move to new header. (nonexistent_local_time::_M_make_what_str): Define correctly. (ambiguous_local_time::_M_make_what_str): Likewise. * include/bits/chrono_io.h: New file. * src/c++20/tzdb.cc (operator<<(ostream&, const Rule&)): Use new ostream output for month and weekday types. * testsuite/20_util/duration/io.cc: Test std::format support. * testsuite/std/time/exceptions.cc: Check what() strings. * testsuite/std/time/syn_c++20.cc: Uncomment local_time_format. * testsuite/std/time/time_zone/get_info_local.cc: Enable check for formatted output of local_info objects. * testsuite/std/time/clock/file/io.cc: New test. * testsuite/std/time/clock/gps/io.cc: New test. * testsuite/std/time/clock/system/io.cc: New test. * testsuite/std/time/clock/tai/io.cc: New test. * testsuite/std/time/clock/utc/io.cc: New test. * testsuite/std/time/day/io.cc: New test. * testsuite/std/time/format.cc: New test. * testsuite/std/time/hh_mm_ss/io.cc: New test. * testsuite/std/time/month/io.cc: New test. * testsuite/std/time/weekday/io.cc: New test. * testsuite/std/time/year/io.cc: New test. * testsuite/std/time/year_month_day/io.cc: New test.
This commit is contained in:
parent
9247402a29
commit
f99b94865f
21 changed files with 3465 additions and 149 deletions
|
@ -175,6 +175,7 @@ bits_headers = \
|
|||
${bits_srcdir}/char_traits.h \
|
||||
${bits_srcdir}/charconv.h \
|
||||
${bits_srcdir}/chrono.h \
|
||||
${bits_srcdir}/chrono_io.h \
|
||||
${bits_srcdir}/codecvt.h \
|
||||
${bits_srcdir}/cow_string.h \
|
||||
${bits_srcdir}/deque.tcc \
|
||||
|
|
|
@ -528,6 +528,7 @@ bits_freestanding = \
|
|||
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/char_traits.h \
|
||||
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/charconv.h \
|
||||
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/chrono.h \
|
||||
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/chrono_io.h \
|
||||
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/codecvt.h \
|
||||
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/cow_string.h \
|
||||
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/deque.tcc \
|
||||
|
|
2469
libstdc++-v3/include/bits/chrono_io.h
Normal file
2469
libstdc++-v3/include/bits/chrono_io.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -45,7 +45,6 @@
|
|||
# include <sstream>
|
||||
# include <string>
|
||||
# include <vector>
|
||||
# include <bits/charconv.h> // __to_chars_len, __to_chars_10_impl
|
||||
# include <bits/stl_algo.h> // upper_bound
|
||||
# include <bits/shared_ptr.h>
|
||||
# include <bits/unique_ptr.h>
|
||||
|
@ -627,8 +626,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
friend constexpr year_month_day
|
||||
operator/(const year_month& __ym, const day& __d) noexcept;
|
||||
|
||||
// TODO: Implement operator<<, to_stream, from_stream.
|
||||
};
|
||||
|
||||
// MONTH
|
||||
|
@ -751,8 +748,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
friend constexpr month_weekday_last
|
||||
operator/(const weekday_last& __wdl, const month& __m) noexcept;
|
||||
|
||||
// TODO: Implement operator<<, to_stream, from_stream.
|
||||
};
|
||||
|
||||
inline constexpr month January{1};
|
||||
|
@ -929,8 +924,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
friend constexpr year_month_weekday_last
|
||||
operator/(const month_weekday_last& __mwdl, const year& __y) noexcept;
|
||||
|
||||
// TODO: Implement operator<<, to_stream, from_stream.
|
||||
};
|
||||
|
||||
// WEEKDAY
|
||||
|
@ -1052,8 +1045,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
auto __n = static_cast<long long>(__x._M_wd) - __y._M_wd;
|
||||
return days{__detail::__modulo(__n, 7)};
|
||||
}
|
||||
|
||||
// TODO: operator<<, from_stream.
|
||||
};
|
||||
|
||||
inline constexpr weekday Sunday{0};
|
||||
|
@ -1110,8 +1101,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
friend constexpr year_month_weekday
|
||||
operator/(const year_month& __ym, const weekday_indexed& __wdi) noexcept;
|
||||
|
||||
// TODO: Implement operator<<.
|
||||
};
|
||||
|
||||
constexpr weekday_indexed
|
||||
|
@ -1151,8 +1140,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
friend constexpr year_month_weekday_last
|
||||
operator/(const year_month& __ym, const weekday_last& __wdl) noexcept;
|
||||
|
||||
// TODO: Implement operator<<.
|
||||
};
|
||||
|
||||
constexpr weekday_last
|
||||
|
@ -1224,8 +1211,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
friend constexpr year_month_day
|
||||
operator/(const month_day& __md, int __y) noexcept;
|
||||
|
||||
// TODO: Implement operator<<, from_stream.
|
||||
};
|
||||
|
||||
// MONTH_DAY_LAST
|
||||
|
@ -1278,8 +1263,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
friend constexpr year_month_day_last
|
||||
operator/(const month_day_last& __mdl, int __y) noexcept;
|
||||
|
||||
// TODO: Implement operator<<.
|
||||
};
|
||||
|
||||
// MONTH_WEEKDAY
|
||||
|
@ -1339,8 +1322,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
friend constexpr year_month_weekday
|
||||
operator/(const month_weekday& __mwd, int __y) noexcept;
|
||||
|
||||
// TODO: Implement operator<<.
|
||||
};
|
||||
|
||||
// MONTH_WEEKDAY_LAST
|
||||
|
@ -1401,8 +1382,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
friend constexpr year_month_weekday_last
|
||||
operator/(const month_weekday_last& __mwdl, int __y) noexcept;
|
||||
|
||||
// TODO: Implement operator<<.
|
||||
};
|
||||
|
||||
// YEAR_MONTH
|
||||
|
@ -1544,8 +1523,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
friend constexpr year_month_day_last
|
||||
operator/(const year_month& __ym, last_spec) noexcept;
|
||||
|
||||
// TODO: Implement operator<<, from_stream.
|
||||
};
|
||||
|
||||
// YEAR_MONTH_DAY
|
||||
|
@ -1697,8 +1674,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
friend constexpr year_month_day
|
||||
operator/(const month_day& __md, int __y) noexcept
|
||||
{ return chrono::year(__y) / __md; }
|
||||
|
||||
// TODO: Implement operator<<, from_stream.
|
||||
};
|
||||
|
||||
// Construct from days since 1970/01/01.
|
||||
|
@ -1928,8 +1903,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
friend constexpr year_month_day_last
|
||||
operator/(const chrono::month_day_last& __mdl, int __y) noexcept
|
||||
{ return chrono::year(__y) / __mdl; }
|
||||
|
||||
// TODO: Implement operator<<.
|
||||
};
|
||||
|
||||
// year_month_day ctor from year_month_day_last
|
||||
|
@ -2118,8 +2091,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
friend constexpr year_month_weekday
|
||||
operator/(const month_weekday& __mwd, int __y) noexcept
|
||||
{ return chrono::year(__y) / __mwd; }
|
||||
|
||||
// TODO: Implement operator<<.
|
||||
};
|
||||
|
||||
// YEAR_MONTH_WEEKDAY_LAST
|
||||
|
@ -2267,8 +2238,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
friend constexpr year_month_weekday_last
|
||||
operator/(const chrono::month_weekday_last& __mwdl, int __y) noexcept
|
||||
{ return chrono::year(__y) / __mwdl; }
|
||||
|
||||
// TODO: Implement operator<<.
|
||||
};
|
||||
|
||||
// HH_MM_SS
|
||||
|
@ -2284,6 +2253,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
__r *= 10;
|
||||
return __r;
|
||||
}
|
||||
|
||||
template<typename _Duration> struct __utc_leap_second;
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
|
@ -2389,8 +2360,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
return _M_h + _M_m + _M_s + subseconds();
|
||||
}
|
||||
|
||||
// TODO: Implement operator<<.
|
||||
|
||||
private:
|
||||
static constexpr bool _S_is_unsigned
|
||||
= __and_v<is_integral<typename _Duration::rep>,
|
||||
|
@ -2459,8 +2428,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
__byte_duration<ratio<1>> _M_s{};
|
||||
bool _M_is_neg{};
|
||||
__subseconds<precision> _M_ss{};
|
||||
|
||||
template<typename> friend struct __detail::__utc_leap_second;
|
||||
};
|
||||
|
||||
/// @cond undocumented
|
||||
namespace __detail
|
||||
{
|
||||
// Represents a time that is within a leap second insertion.
|
||||
template<typename _Duration>
|
||||
struct __utc_leap_second
|
||||
{
|
||||
explicit
|
||||
__utc_leap_second(const sys_time<_Duration>& __s)
|
||||
: _M_date(chrono::floor<days>(__s)), _M_time(__s - _M_date)
|
||||
{
|
||||
++_M_time._M_s;
|
||||
}
|
||||
|
||||
sys_days _M_date;
|
||||
hh_mm_ss<common_type_t<_Duration, days>> _M_time;
|
||||
};
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
// 12/24 HOURS FUNCTIONS
|
||||
|
||||
constexpr bool
|
||||
|
@ -2540,9 +2531,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
_S_make_what_str(const local_time<_Duration>& __tp,
|
||||
const local_info& __i)
|
||||
{
|
||||
#if 1
|
||||
return "local time is non-existent";
|
||||
#else
|
||||
std::ostringstream __os;
|
||||
__os << __tp << " is in a gap between\n"
|
||||
<< local_seconds(__i.first.end.time_since_epoch())
|
||||
|
@ -2552,7 +2540,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
<< " which are both equivalent to\n"
|
||||
<< __i.first.end << " UTC";
|
||||
return std::move(__os).str();
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2571,9 +2558,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
_S_make_what_str(const local_time<_Duration>& __tp,
|
||||
const local_info& __i)
|
||||
{
|
||||
#if 1
|
||||
return "local time is ambiguous";
|
||||
#else
|
||||
std::ostringstream __os;
|
||||
__os << __tp << " is ambiguous. It could be\n"
|
||||
<< __tp << ' ' << __i.first.abbrev << " == "
|
||||
|
@ -2581,7 +2565,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
<< __tp << ' ' << __i.second.abbrev << " == "
|
||||
<< __tp - __i.second.offset << " UTC";
|
||||
return std::move(__os).str();
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -3329,106 +3312,15 @@ namespace __detail
|
|||
/// @}
|
||||
} // inline namespace chrono_literals
|
||||
} // inline namespace literals
|
||||
|
||||
namespace chrono
|
||||
{
|
||||
/// @addtogroup chrono
|
||||
/// @{
|
||||
|
||||
/// @cond undocumented
|
||||
namespace __detail
|
||||
{
|
||||
template<typename _Period>
|
||||
const char*
|
||||
__units_suffix_misc(char* __buf, size_t __n) noexcept
|
||||
{
|
||||
namespace __tc = std::__detail;
|
||||
char* __p = __buf;
|
||||
__p[0] = '[';
|
||||
unsigned __nlen = __tc::__to_chars_len((uintmax_t)_Period::num);
|
||||
__tc::__to_chars_10_impl(__p + 1, __nlen, (uintmax_t)_Period::num);
|
||||
__p += 1 + __nlen;
|
||||
if constexpr (_Period::den != 1)
|
||||
{
|
||||
__p[0] = '/';
|
||||
unsigned __dlen = __tc::__to_chars_len((uintmax_t)_Period::den);
|
||||
__tc::__to_chars_10_impl(__p + 1, __dlen, (uintmax_t)_Period::den);
|
||||
__p += 1 + __dlen;
|
||||
}
|
||||
__p[0] = ']';
|
||||
__p[1] = 's';
|
||||
__p[2] = '\0';
|
||||
return __buf;
|
||||
}
|
||||
|
||||
template<typename _Period, typename _CharT>
|
||||
auto
|
||||
__units_suffix(char* __buf, size_t __n) noexcept
|
||||
{
|
||||
#define _GLIBCXX_UNITS_SUFFIX(period, suffix) \
|
||||
if constexpr (is_same_v<_Period, period>) \
|
||||
{ \
|
||||
if constexpr (is_same_v<_CharT, wchar_t>) \
|
||||
return L##suffix; \
|
||||
else \
|
||||
return suffix; \
|
||||
} \
|
||||
else
|
||||
|
||||
_GLIBCXX_UNITS_SUFFIX(atto, "as")
|
||||
_GLIBCXX_UNITS_SUFFIX(femto, "fs")
|
||||
_GLIBCXX_UNITS_SUFFIX(pico, "ps")
|
||||
_GLIBCXX_UNITS_SUFFIX(nano, "ns")
|
||||
_GLIBCXX_UNITS_SUFFIX(micro, "\u00b5s")
|
||||
_GLIBCXX_UNITS_SUFFIX(milli, "ms")
|
||||
_GLIBCXX_UNITS_SUFFIX(centi, "cs")
|
||||
_GLIBCXX_UNITS_SUFFIX(deci, "ds")
|
||||
_GLIBCXX_UNITS_SUFFIX(ratio<1>, "s")
|
||||
_GLIBCXX_UNITS_SUFFIX(deca, "das")
|
||||
_GLIBCXX_UNITS_SUFFIX(hecto, "hs")
|
||||
_GLIBCXX_UNITS_SUFFIX(kilo, "ks")
|
||||
_GLIBCXX_UNITS_SUFFIX(mega, "Ms")
|
||||
_GLIBCXX_UNITS_SUFFIX(giga, "Gs")
|
||||
_GLIBCXX_UNITS_SUFFIX(tera, "Ts")
|
||||
_GLIBCXX_UNITS_SUFFIX(tera, "Ts")
|
||||
_GLIBCXX_UNITS_SUFFIX(peta, "Ps")
|
||||
_GLIBCXX_UNITS_SUFFIX(exa, "Es")
|
||||
_GLIBCXX_UNITS_SUFFIX(ratio<60>, "min")
|
||||
_GLIBCXX_UNITS_SUFFIX(ratio<3600>, "h")
|
||||
_GLIBCXX_UNITS_SUFFIX(ratio<86400>, "d")
|
||||
#undef _GLIBCXX_UNITS_SUFFIX
|
||||
return __detail::__units_suffix_misc<_Period>(__buf, __n);
|
||||
}
|
||||
} // namespace __detail
|
||||
/// @endcond
|
||||
|
||||
template<typename _CharT, typename _Traits,
|
||||
typename _Rep, typename _Period>
|
||||
inline basic_ostream<_CharT, _Traits>&
|
||||
operator<<(std::basic_ostream<_CharT, _Traits>& __os,
|
||||
const duration<_Rep, _Period>& __d)
|
||||
{
|
||||
using period = typename _Period::type;
|
||||
char __buf[sizeof("[/]s") + 2 * numeric_limits<intmax_t>::digits10];
|
||||
std::basic_ostringstream<_CharT, _Traits> __s;
|
||||
__s.flags(__os.flags());
|
||||
__s.imbue(__os.getloc());
|
||||
__s.precision(__os.precision());
|
||||
__s << __d.count();
|
||||
__s << __detail::__units_suffix<period, _CharT>(__buf, sizeof(__buf));
|
||||
__os << std::move(__s).str();
|
||||
return __os;
|
||||
}
|
||||
|
||||
// TODO: from_stream for duration
|
||||
|
||||
/// @} group chrono
|
||||
} // namespace chrono
|
||||
#endif // C++20
|
||||
|
||||
_GLIBCXX_END_NAMESPACE_VERSION
|
||||
} // namespace std
|
||||
|
||||
#if __cplusplus >= 202002L
|
||||
# include <bits/chrono_io.h>
|
||||
#endif
|
||||
|
||||
#endif // C++11
|
||||
|
||||
#endif //_GLIBCXX_CHRONO
|
||||
|
|
|
@ -511,27 +511,25 @@ namespace std::chrono
|
|||
friend ostream& operator<<(ostream& out, const Rule& r)
|
||||
{
|
||||
out << "Rule " << r.name << ' ' << (int)r.from << ' ' << (int)r.to
|
||||
<< ' ' << (unsigned)r.when.day.get_month() << ' ';
|
||||
<< ' ' << r.when.day.get_month() << ' ';
|
||||
switch (r.when.day.kind)
|
||||
{
|
||||
case on_day::DayOfMonth:
|
||||
out << (unsigned)r.when.day.get_day();
|
||||
break;
|
||||
case on_day::LastWeekday:
|
||||
out << "last" << weekday(r.when.day.day_of_week).c_encoding();
|
||||
out << "last" << weekday(r.when.day.day_of_week);
|
||||
break;
|
||||
case on_day::LessEq:
|
||||
out << weekday(r.when.day.day_of_week).c_encoding() << " <= "
|
||||
out << weekday(r.when.day.day_of_week) << " <= "
|
||||
<< r.when.day.day_of_month;
|
||||
break;
|
||||
case on_day::GreaterEq:
|
||||
out << weekday(r.when.day.day_of_week).c_encoding() << " >= "
|
||||
out << weekday(r.when.day.day_of_week) << " >= "
|
||||
<< r.when.day.day_of_month;
|
||||
break;
|
||||
}
|
||||
hh_mm_ss hms(r.when.time);
|
||||
out << ' ' << hms.hours().count() << ':' << hms.minutes().count()
|
||||
<< ':' << hms.seconds().count() << "wusd"[r.when.indicator];
|
||||
out << ' ' << hh_mm_ss(r.when.time) << "wusd"[r.when.indicator];
|
||||
out << ' ' << r.save.count();
|
||||
if (!r.letters.empty())
|
||||
out << ' ' << r.letters;
|
||||
|
|
|
@ -47,8 +47,56 @@ test02()
|
|||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
test_format()
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
auto s = std::format("{} {}", 1h + 23min + 45s, -42min);
|
||||
VERIFY( s == "5025s -42min" );
|
||||
s = std::format("{:%j} {:%j} {:%j}", 1h + 23min + 45s, 75h, -99h);
|
||||
VERIFY( s == "0 3 -4" );
|
||||
s = std::format("{:%T = %H:%M:%S}", 1h + 23min + 45s);
|
||||
VERIFY( s == "01:23:45 = 01:23:45" );
|
||||
s = std::format("{:%Q} {:%q} {:%Q%q}", 6min + 1s, 44min, -22h);
|
||||
VERIFY( s == "361 min -22h" );
|
||||
|
||||
std::wstring ws = std::format(L"{:%Q%q}", 81s);
|
||||
VERIFY( ws == L"81s" );
|
||||
|
||||
// Only print '-' on numeric fields for negative durations:
|
||||
s = std::format("{:%Q} {:%q} {:%q%Q}", -21h, -20h, -19h);
|
||||
VERIFY( s == "-21 h h-19" );
|
||||
s = std::format("{:%p} {:%p%H}", -2h, -13h);
|
||||
VERIFY( s == "AM PM-13" );
|
||||
s = std::format("{:%t} {:%t%M}", -2h, -123s);
|
||||
VERIFY( s == "\t \t-02" );
|
||||
|
||||
std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
|
||||
std::string_view my_specs = "HIjMpqQrRSTX";
|
||||
for (char c : specs)
|
||||
{
|
||||
char fmt[] = { '{', ':', '%', c, '}' };
|
||||
try
|
||||
{
|
||||
(void) std::vformat(std::string_view(fmt, 5), std::make_format_args(1s));
|
||||
// The call above should throw for any conversion-spec not in my_specs:
|
||||
VERIFY(my_specs.find(c) != my_specs.npos);
|
||||
}
|
||||
catch (const std::format_error& e)
|
||||
{
|
||||
VERIFY(my_specs.find(c) == my_specs.npos);
|
||||
std::string_view s = e.what();
|
||||
// Libstdc++-specific message:
|
||||
VERIFY(s.find("format argument does not contain the information "
|
||||
"required by the chrono-specs") != s.npos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test01();
|
||||
test02();
|
||||
test_format();
|
||||
// TODO: test_parse();
|
||||
}
|
||||
|
|
23
libstdc++-v3/testsuite/std/time/clock/file/io.cc
Normal file
23
libstdc++-v3/testsuite/std/time/clock/file/io.cc
Normal file
|
@ -0,0 +1,23 @@
|
|||
// { dg-options "-std=gnu++20" }
|
||||
// { dg-do run { target c++20 } }
|
||||
|
||||
#include <chrono>
|
||||
#include <sstream>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
void
|
||||
test_ostream()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
|
||||
file_time<file_clock::duration> t = file_clock::now();
|
||||
std::ostringstream ss1, ss2;
|
||||
ss1 << floor<seconds>(t);
|
||||
ss2 << floor<seconds>(clock_cast<system_clock>(t));
|
||||
VERIFY( ss1.str() == ss2.str() );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_ostream();
|
||||
}
|
24
libstdc++-v3/testsuite/std/time/clock/gps/io.cc
Normal file
24
libstdc++-v3/testsuite/std/time/clock/gps/io.cc
Normal file
|
@ -0,0 +1,24 @@
|
|||
// { dg-options "-std=gnu++20" }
|
||||
// { dg-do run { target c++20 } }
|
||||
|
||||
#include <chrono>
|
||||
#include <format>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
void
|
||||
test01()
|
||||
{
|
||||
using std::format;
|
||||
using namespace std::chrono;
|
||||
|
||||
auto st = sys_days{2000y/January/1};
|
||||
auto gt = clock_cast<gps_clock>(st);
|
||||
|
||||
auto s = format("{0:%F %T %Z} == {1:%F %T %Z}", st, gt);
|
||||
VERIFY( s == "2000-01-01 00:00:00 UTC == 2000-01-01 00:00:13 GPS" );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test01();
|
||||
}
|
72
libstdc++-v3/testsuite/std/time/clock/system/io.cc
Normal file
72
libstdc++-v3/testsuite/std/time/clock/system/io.cc
Normal file
|
@ -0,0 +1,72 @@
|
|||
// { dg-options "-std=gnu++20" }
|
||||
// { dg-do run { target c++20 } }
|
||||
|
||||
#include <chrono>
|
||||
#include <sstream>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
void
|
||||
test_ostream()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
std::stringstream ss;
|
||||
ss << sys_seconds{0s} << '\n'; // 1970-01-01 00:00:00
|
||||
ss << sys_seconds{946'684'800s} << '\n'; // 2000-01-01 00:00:00
|
||||
ss << sys_seconds{946'688'523s} << '\n'; // 2000-01-01 01:02:03
|
||||
std::string s1, s2, s3;
|
||||
std::getline(ss, s1);
|
||||
std::getline(ss, s2);
|
||||
std::getline(ss, s3);
|
||||
VERIFY( s1 == "1970-01-01 00:00:00" );
|
||||
VERIFY( s2 == "2000-01-01 00:00:00" );
|
||||
VERIFY( s3 == "2000-01-01 01:02:03" );
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
concept stream_insertable
|
||||
= requires (std::ostream& out, const T& t) { out << t; };
|
||||
|
||||
// operator<<(ostream&, const sys_time<D>&) is constrained to not
|
||||
// allow floating-point types or periods of days or greater.
|
||||
using fp_sys_time = std::chrono::sys_time<std::chrono::duration<float>>;
|
||||
static_assert( !stream_insertable<fp_sys_time> );
|
||||
|
||||
// But there is an overload for sys_days.
|
||||
static_assert( stream_insertable<std::chrono::sys_days> );
|
||||
|
||||
void
|
||||
test_format()
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
std::chrono::sys_time<std::chrono::milliseconds> t(1671470785708ms);
|
||||
|
||||
// Every conversion specifier is valid for a sys_time except %q and %Q.
|
||||
|
||||
std::string s = std::format("{:%a | %A | %b | %B | %c"
|
||||
" | %C | %d | %D | %e | %F | %g | %G | %h"
|
||||
" | %H | %I | %j | %m | %M | %p | %r | %R"
|
||||
" | %S | %T | %u | %U | %V | %w | %W | %x"
|
||||
" | %X | %y | %Y | %z | %Z}", t);
|
||||
VERIFY( s == "Mon | Monday | Dec | December | Mon Dec 19 17:26:25.708 2022"
|
||||
" | 20 | 19 | 12/19/22 | 19 | 2022-12-19 | 22 | 2022 | Dec"
|
||||
" | 17 | 05 | 353 | 12 | 26 | PM | 05:26:25.708 PM | 17:26"
|
||||
" | 25.708 | 17:26:25.708 | 1 | 51 | 51 | 1 | 51 | 12/19/22"
|
||||
" | 17:26:25.708 | 22 | 2022 | +0000 | UTC" );
|
||||
|
||||
std::wstring ws = std::format(L"{:%a | %A | %b | %B | %c"
|
||||
" | %C | %d | %D | %e | %F | %g | %G | %h"
|
||||
" | %H | %I | %j | %m | %M | %p | %r | %R"
|
||||
" | %S | %T | %u | %U | %V | %w | %W | %x"
|
||||
" | %X | %y | %Y | %z | %Z}", t);
|
||||
VERIFY( ws == L"Mon | Monday | Dec | December | Mon Dec 19 17:26:25.708 2022"
|
||||
" | 20 | 19 | 12/19/22 | 19 | 2022-12-19 | 22 | 2022 | Dec"
|
||||
" | 17 | 05 | 353 | 12 | 26 | PM | 05:26:25.708 PM | 17:26"
|
||||
" | 25.708 | 17:26:25.708 | 1 | 51 | 51 | 1 | 51 | 12/19/22"
|
||||
" | 17:26:25.708 | 22 | 2022 | +0000 | UTC" );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_ostream();
|
||||
test_format();
|
||||
}
|
24
libstdc++-v3/testsuite/std/time/clock/tai/io.cc
Normal file
24
libstdc++-v3/testsuite/std/time/clock/tai/io.cc
Normal file
|
@ -0,0 +1,24 @@
|
|||
// { dg-options "-std=gnu++20" }
|
||||
// { dg-do run { target c++20 } }
|
||||
|
||||
#include <chrono>
|
||||
#include <format>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
void
|
||||
test01()
|
||||
{
|
||||
using std::format;
|
||||
using namespace std::chrono;
|
||||
|
||||
auto st = sys_days{2000y/January/1};
|
||||
auto tt = clock_cast<tai_clock>(st);
|
||||
|
||||
auto s = format("{0:%F %T %Z} == {1:%F %T %Z}", st, tt);
|
||||
VERIFY( s == "2000-01-01 00:00:00 UTC == 2000-01-01 00:00:32 TAI" );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test01();
|
||||
}
|
120
libstdc++-v3/testsuite/std/time/clock/utc/io.cc
Normal file
120
libstdc++-v3/testsuite/std/time/clock/utc/io.cc
Normal file
|
@ -0,0 +1,120 @@
|
|||
// { dg-options "-std=gnu++20" }
|
||||
// { dg-do run { target c++20 } }
|
||||
|
||||
#include <chrono>
|
||||
#include <sstream>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
void
|
||||
test_ostream()
|
||||
{
|
||||
using std::ostringstream;
|
||||
using namespace std::chrono;
|
||||
|
||||
auto t = sys_days{July/1/2015} - 500ms;
|
||||
auto u = clock_cast<utc_clock>(t);
|
||||
|
||||
std::string_view results[] = {
|
||||
"2015-06-30 23:59:59.500 UTC",
|
||||
"2015-06-30 23:59:59.750 UTC",
|
||||
"2015-06-30 23:59:60.000 UTC",
|
||||
"2015-06-30 23:59:60.250 UTC",
|
||||
"2015-06-30 23:59:60.500 UTC",
|
||||
"2015-06-30 23:59:60.750 UTC",
|
||||
"2015-07-01 00:00:00.000 UTC",
|
||||
"2015-07-01 00:00:00.250 UTC",
|
||||
};
|
||||
|
||||
for (auto result : results)
|
||||
{
|
||||
ostringstream out;
|
||||
out << u << " UTC";
|
||||
VERIFY( out.str() == result );
|
||||
u += 250ms;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
test_format()
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
std::chrono::utc_time<std::chrono::milliseconds> t(1671470812708ms);
|
||||
|
||||
// Every conversion specifier is valid for a utc_time except %q and %Q.
|
||||
std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
|
||||
std::string_view badspecs = "qQ";
|
||||
|
||||
std::ostringstream ss;
|
||||
std::wostringstream wss;
|
||||
|
||||
for (char c : specs)
|
||||
{
|
||||
char fmt[] = { '{', ':', '%', c, '}' };
|
||||
try
|
||||
{
|
||||
ss << std::vformat(std::string_view(fmt, 5),
|
||||
std::make_format_args(t));
|
||||
ss << " | ";
|
||||
// The call above should throw for any conversion-spec in badspecs:
|
||||
VERIFY(badspecs.find(c) == badspecs.npos);
|
||||
|
||||
}
|
||||
catch (const std::format_error& e)
|
||||
{
|
||||
VERIFY(badspecs.find(c) != badspecs.npos);
|
||||
std::string_view s = e.what();
|
||||
// Libstdc++-specific message:
|
||||
VERIFY(s.find("format argument does not contain the information "
|
||||
"required by the chrono-specs") != s.npos);
|
||||
}
|
||||
|
||||
wchar_t wfmt[] = { L'{', L':', L'%', c, L'}' };
|
||||
try
|
||||
{
|
||||
wss << std::vformat(std::wstring_view(wfmt, 5),
|
||||
std::make_wformat_args(t));
|
||||
wss << L" | ";
|
||||
// The call above should throw for any conversion-spec in badspecs:
|
||||
VERIFY(badspecs.find(c) == badspecs.npos);
|
||||
}
|
||||
catch (const std::format_error& e)
|
||||
{
|
||||
VERIFY(badspecs.find(c) != badspecs.npos);
|
||||
std::string_view s = e.what();
|
||||
// Libstdc++-specific message:
|
||||
VERIFY(s.find("format argument does not contain the information "
|
||||
"required by the chrono-specs") != s.npos);
|
||||
}
|
||||
}
|
||||
|
||||
std::string s = ss.str();
|
||||
VERIFY( s == "Mon | Monday | Dec | December | Mon Dec 19 17:26:25.708 2022"
|
||||
" | 20 | 19 | 12/19/22 | 19 | 2022-12-19 | 22 | 2022 | Dec"
|
||||
" | 17 | 05 | 353 | 12 | 26 | PM | 05:26:25.708 PM | 17:26"
|
||||
" | 25.708 | 17:26:25.708 | 1 | 51 | 51 | 1 | 51 | 12/19/22"
|
||||
" | 17:26:25.708 | 22 | 2022 | +0000 | UTC | " );
|
||||
|
||||
std::wstring ws = wss.str();
|
||||
VERIFY( ws == L"Mon | Monday | Dec | December | Mon Dec 19 17:26:25.708 2022"
|
||||
" | 20 | 19 | 12/19/22 | 19 | 2022-12-19 | 22 | 2022 | Dec"
|
||||
" | 17 | 05 | 353 | 12 | 26 | PM | 05:26:25.708 PM | 17:26"
|
||||
" | 25.708 | 17:26:25.708 | 1 | 51 | 51 | 1 | 51 | 12/19/22"
|
||||
" | 17:26:25.708 | 22 | 2022 | +0000 | UTC | " );
|
||||
|
||||
std::chrono::utc_seconds leap(1483228800s + 26s); // 1 Jan 2017
|
||||
s = std::format("{:%T}", leap - 1s);
|
||||
VERIFY( s == "23:59:59" );
|
||||
s = std::format("{:%T}", leap);
|
||||
VERIFY( s == "23:59:60" );
|
||||
s = std::format("{:%T}", leap + 10ms);
|
||||
VERIFY( s == "23:59:60.010" );
|
||||
|
||||
s = std::format("{:%T}", leap + 1s);
|
||||
VERIFY( s == "00:00:00" );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_ostream();
|
||||
test_format();
|
||||
}
|
75
libstdc++-v3/testsuite/std/time/day/io.cc
Normal file
75
libstdc++-v3/testsuite/std/time/day/io.cc
Normal file
|
@ -0,0 +1,75 @@
|
|||
// { dg-options "-std=gnu++20" }
|
||||
// { dg-do run { target c++20 } }
|
||||
// { dg-require-namedlocale "fr_FR.ISO8859-15" }
|
||||
|
||||
#include <chrono>
|
||||
#include <sstream>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
void
|
||||
test_ostream()
|
||||
{
|
||||
using std::ostringstream;
|
||||
using namespace std::chrono;
|
||||
|
||||
ostringstream ss;
|
||||
ss << day(1) << ' ' << day(11) << ' ' << day(21) << ' ' << day(31)
|
||||
<< ' ' << day(41);
|
||||
auto s = ss.str();
|
||||
VERIFY( s == "01 11 21 31 41 is not a valid day" );
|
||||
|
||||
ss.str("");
|
||||
ss.imbue(std::locale(ISO_8859(15,fr_FR)));
|
||||
ss << day(1);
|
||||
VERIFY( ss.str() == "01" );
|
||||
}
|
||||
|
||||
void
|
||||
test_format()
|
||||
{
|
||||
using std::chrono::day;
|
||||
|
||||
auto s = std::format("{:%d%%%e%t}{:%d%%%e%n}", day(1), day(11));
|
||||
VERIFY( s == "01% 1\t11%11\n" );
|
||||
auto ws = std::format(L"{:%d%%%e%t}{:%d%%%e%n}", day(1), day(11));
|
||||
VERIFY( ws == L"01% 1\t11%11\n" );
|
||||
|
||||
VERIFY( std::format("{} {}", day(8), day(0)) == "08 00 is not a valid day" );
|
||||
|
||||
s = std::format("{:%Od}", day(1));
|
||||
VERIFY( s == "01" );
|
||||
s = std::format(std::locale::classic(), "{:%Od}", day(1));
|
||||
VERIFY( s == "01" );
|
||||
s = std::format(std::locale::classic(), "{:L%Od}", day(1));
|
||||
VERIFY( s == "01" );
|
||||
// TODO test "{:L%Od}" with locale that has alternative numeric rep.
|
||||
|
||||
std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
|
||||
std::string_view my_specs = "de";
|
||||
for (char c : specs)
|
||||
{
|
||||
char fmt[] = { '{', ':', '%', c, '}' };
|
||||
try
|
||||
{
|
||||
(void) std::vformat(std::string_view(fmt, 5),
|
||||
std::make_format_args(day(1)));
|
||||
// The call above should throw for any conversion-spec not in my_specs:
|
||||
VERIFY(my_specs.find(c) != my_specs.npos);
|
||||
}
|
||||
catch (const std::format_error& e)
|
||||
{
|
||||
VERIFY(my_specs.find(c) == my_specs.npos);
|
||||
std::string_view s = e.what();
|
||||
// Libstdc++-specific message:
|
||||
VERIFY(s.find("format argument does not contain the information "
|
||||
"required by the chrono-specs") != s.npos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_ostream();
|
||||
test_format();
|
||||
// TODO: test_parse();
|
||||
}
|
|
@ -20,7 +20,7 @@ test_nonexistent()
|
|||
local_days{Sunday[2]/March/2016} + 2h + 30min};
|
||||
VERIFY(false);
|
||||
} catch (const nonexistent_local_time& e) {
|
||||
// VERIFY( e.what() == expected );
|
||||
VERIFY( e.what() == expected );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ test_ambiguous()
|
|||
local_days{Sunday[1]/November/2016} + 1h + 30min};
|
||||
VERIFY(false);
|
||||
} catch (const ambiguous_local_time& e) {
|
||||
// VERIFY( e.what() == expected );
|
||||
VERIFY( e.what() == expected );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
117
libstdc++-v3/testsuite/std/time/format.cc
Normal file
117
libstdc++-v3/testsuite/std/time/format.cc
Normal file
|
@ -0,0 +1,117 @@
|
|||
// { dg-options "-std=gnu++20" }
|
||||
// { dg-do run { target c++20 } }
|
||||
|
||||
#include <chrono>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
void
|
||||
test_format_strings()
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
// valid format strings
|
||||
VERIFY( std::format("{}", 1s) == "1s" );
|
||||
VERIFY( std::format("{:}", 1s) == "1s" );
|
||||
VERIFY( std::format("{:L}", 1s) == "1s" );
|
||||
VERIFY( std::format("{:%%%n%t}", 1s) == "%\n\t" );
|
||||
VERIFY( std::format("{:L%%%n%t}", 1s) == "%\n\t" );
|
||||
VERIFY( std::format("{:4%%}", 1s) == "% " );
|
||||
VERIFY( std::format("{:4L%%}", 1s) == "% " );
|
||||
VERIFY( std::format("{: >4}", 1s) == " 1s" );
|
||||
VERIFY( std::format("{: <4}", 1s) == "1s " );
|
||||
VERIFY( std::format("{: <4L}", 1s) == "1s " );
|
||||
VERIFY( std::format("{: >4%%}", 1s) == " %" );
|
||||
VERIFY( std::format("{: >4L%%}", 1s) == " %" );
|
||||
VERIFY( std::format("{: ^4%%}", 1s) == " % " );
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
bool
|
||||
is_format_string_for(const char* str, Args&&... args)
|
||||
{
|
||||
try {
|
||||
(void) std::vformat(str, std::make_format_args(args...));
|
||||
return true;
|
||||
} catch (const std::format_error&) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
test_bad_format_strings()
|
||||
{
|
||||
std::chrono::sys_seconds t{};
|
||||
|
||||
// literal '%' must be formatted as "%%"
|
||||
VERIFY( not is_format_string_for("{:%}", t) );
|
||||
|
||||
// chrono-specs must start with '%'
|
||||
VERIFY( not is_format_string_for("{:a%}", t) );
|
||||
VERIFY( not is_format_string_for("{:La%}", t) );
|
||||
|
||||
// '{' not valid in chrono-specs
|
||||
VERIFY( not is_format_string_for("{:%%{{%%}", t) );
|
||||
|
||||
// padding with leading zero not valid for chrono types
|
||||
VERIFY( not is_format_string_for("{:04%T}", t) );
|
||||
|
||||
// precision only valid for chrono::duration types with floating-point rep.
|
||||
VERIFY( not is_format_string_for("{:.4}", t) );
|
||||
|
||||
// unfinished format string
|
||||
VERIFY( not is_format_string_for("{:", t) );
|
||||
|
||||
// dangling modifiers
|
||||
VERIFY( not is_format_string_for("{:%E}", t) );
|
||||
VERIFY( not is_format_string_for("{:%O}", t) );
|
||||
|
||||
// modifier not valid for conversion specifier
|
||||
VERIFY( not is_format_string_for("{:%Ea}", t) );
|
||||
VERIFY( not is_format_string_for("{:%Oa}", t) );
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
struct move_only_iterator
|
||||
{
|
||||
using iterator = I;
|
||||
using value_type = iterator::value_type;
|
||||
using difference_type = iterator::difference_type;
|
||||
using iterator_category = std::output_iterator_tag;
|
||||
|
||||
move_only_iterator(iterator b) : base_(b) { }
|
||||
move_only_iterator(move_only_iterator&&) = default;
|
||||
move_only_iterator& operator=(move_only_iterator&&) = default;
|
||||
|
||||
move_only_iterator& operator++() { ++base_; return *this; }
|
||||
move_only_iterator operator++(int) { auto tmp = *this; ++base_; return tmp; }
|
||||
|
||||
decltype(auto) operator*() { return *base_; }
|
||||
|
||||
private:
|
||||
iterator base_;
|
||||
};
|
||||
|
||||
void
|
||||
test_move_only_iterator()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
utc_seconds ut(1671543754s);
|
||||
sys_seconds st(1671543727s);
|
||||
|
||||
std::string str;
|
||||
move_only_iterator mo(std::back_inserter(str));
|
||||
std::format_to(std::move(mo), "{:%F} {:%T} {:%Q}", ut, st, 1s);
|
||||
VERIFY( str == "2022-12-20 13:42:07 1" );
|
||||
|
||||
std::vector<wchar_t> vec;
|
||||
move_only_iterator wmo(std::back_inserter(vec));
|
||||
std::format_to(std::move(wmo), L"{:%F} {:%T} {:%Q}", ut, st, 2s);
|
||||
VERIFY( std::wstring_view(vec.data(), vec.size()) == L"2022-12-20 13:42:07 2" );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_format_strings();
|
||||
test_bad_format_strings();
|
||||
test_move_only_iterator();
|
||||
}
|
46
libstdc++-v3/testsuite/std/time/hh_mm_ss/io.cc
Normal file
46
libstdc++-v3/testsuite/std/time/hh_mm_ss/io.cc
Normal file
|
@ -0,0 +1,46 @@
|
|||
// { dg-options "-std=gnu++20" }
|
||||
// { dg-do run { target c++20 } }
|
||||
|
||||
#include <chrono>
|
||||
#include <sstream>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
void
|
||||
test01()
|
||||
{
|
||||
using std::ostringstream;
|
||||
using std::chrono::hh_mm_ss;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
std::locale::global(std::locale::classic());
|
||||
|
||||
{
|
||||
hh_mm_ss hms{-4083007ms};
|
||||
ostringstream out;
|
||||
out << hms;
|
||||
VERIFY( out.str() == "-01:08:03.007" );
|
||||
}
|
||||
|
||||
{
|
||||
hh_mm_ss hms{4083007ms};
|
||||
ostringstream out;
|
||||
out << hms;
|
||||
VERIFY( out.str() == "01:08:03.007" );
|
||||
}
|
||||
|
||||
{
|
||||
hh_mm_ss hms{65745123ms};
|
||||
ostringstream out;
|
||||
out << hms;
|
||||
VERIFY( out.str() == "18:15:45.123" );
|
||||
}
|
||||
|
||||
ostringstream out;
|
||||
out << hh_mm_ss{65745s};
|
||||
VERIFY( out.str() == "18:15:45" );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test01();
|
||||
}
|
98
libstdc++-v3/testsuite/std/time/month/io.cc
Normal file
98
libstdc++-v3/testsuite/std/time/month/io.cc
Normal file
|
@ -0,0 +1,98 @@
|
|||
// { dg-options "-std=gnu++20" }
|
||||
// { dg-do run { target c++20 } }
|
||||
// { dg-require-namedlocale "fr_FR.ISO8859-15" }
|
||||
|
||||
#include <chrono>
|
||||
#include <sstream>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
void
|
||||
test_ostream()
|
||||
{
|
||||
using std::ostringstream;
|
||||
using namespace std::chrono;
|
||||
|
||||
ostringstream ss;
|
||||
for (int i = 1; i <= 12; ++i)
|
||||
ss << month(i);
|
||||
VERIFY( ss.str() == "JanFebMarAprMayJunJulAugSepOctNovDec" );
|
||||
ss.str("");
|
||||
ss << month(0) << '|' << month(13);
|
||||
VERIFY( ss.str() == "0 is not a valid month|13 is not a valid month" );
|
||||
|
||||
ss.str("");
|
||||
ss.imbue(std::locale(ISO_8859(15,fr_FR)));
|
||||
ss << month(1);
|
||||
VERIFY( ss.str() == "janv." );
|
||||
}
|
||||
|
||||
void
|
||||
test_format()
|
||||
{
|
||||
using std::chrono::month;
|
||||
|
||||
auto s = std::format("{:%b%%%B%t%m%n}", month(1));
|
||||
VERIFY( s == "Jan%January\t01\n" );
|
||||
auto ws = std::format(L"{:%b%%%B%t%m%n}", month(12));
|
||||
VERIFY( ws == L"Dec%December\t12\n" );
|
||||
|
||||
try
|
||||
{
|
||||
(void) std::format("{:%b}", month(13));
|
||||
VERIFY(false);
|
||||
}
|
||||
catch (const std::format_error&)
|
||||
{
|
||||
}
|
||||
|
||||
s = std::format("{} is OK, but {:L}", month(2), month(13));
|
||||
VERIFY( s == "Feb is OK, but 13 is not a valid month" );
|
||||
|
||||
std::locale loc_fr(ISO_8859(15,fr_FR));
|
||||
|
||||
s = std::format("{:%Om}", month(1));
|
||||
VERIFY( s == "01" );
|
||||
s = std::format(std::locale::classic(), "{:%Om}", month(1));
|
||||
VERIFY( s == "01" );
|
||||
s = std::format(std::locale::classic(), "{:L%Om}", month(1));
|
||||
VERIFY( s == "01" );
|
||||
s = std::format(loc_fr, "{:%Om}", month(1));
|
||||
VERIFY( s == "01" );
|
||||
s = std::format(loc_fr, "{:L%Om}", month(1));
|
||||
VERIFY( s == "01" );
|
||||
// TODO test "{:L%Om}" with locale that has alternative numeric rep.
|
||||
|
||||
s = std::format(loc_fr, "{:%b}", month(1));
|
||||
VERIFY( s == "Jan" );
|
||||
s = std::format(loc_fr, "{:L%b}", month(1));
|
||||
VERIFY( s == "janv." );
|
||||
|
||||
std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
|
||||
std::string_view my_specs = "bBhm";
|
||||
for (char c : specs)
|
||||
{
|
||||
char fmt[] = { '{', ':', '%', c, '}' };
|
||||
try
|
||||
{
|
||||
(void) std::vformat(std::string_view(fmt, 5),
|
||||
std::make_format_args(month(1)));
|
||||
// The call above should throw for any conversion-spec not in my_specs:
|
||||
VERIFY(my_specs.find(c) != my_specs.npos);
|
||||
}
|
||||
catch (const std::format_error& e)
|
||||
{
|
||||
VERIFY(my_specs.find(c) == my_specs.npos);
|
||||
std::string_view s = e.what();
|
||||
// Libstdc++-specific message:
|
||||
VERIFY(s.find("format argument does not contain the information "
|
||||
"required by the chrono-specs") != s.npos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_ostream();
|
||||
test_format();
|
||||
// TODO: test_parse();
|
||||
}
|
|
@ -124,8 +124,7 @@ namespace __gnu_test
|
|||
using std::chrono::time_zone_link;
|
||||
#endif
|
||||
|
||||
// FIXME
|
||||
// using std::chrono::local_time_format;
|
||||
using std::chrono::local_time_format;
|
||||
|
||||
// FIXME
|
||||
// using std::chrono::parse;
|
||||
|
|
|
@ -148,7 +148,6 @@ test_egypt()
|
|||
VERIFY( info.second.save == 1h );
|
||||
VERIFY( info.second.abbrev == "EEST" );
|
||||
|
||||
#if 0
|
||||
std::ostringstream out;
|
||||
local_seconds lt(local_days(2001y/January/1));
|
||||
const local_days end(2021y/January/1);
|
||||
|
@ -209,7 +208,6 @@ test_egypt()
|
|||
[[2014-09-25 21:00:00,32767-12-31 00:00:00,02:00:00,0min,EET]]
|
||||
)";
|
||||
VERIFY( out.str() == expected );
|
||||
#endif
|
||||
}
|
||||
|
||||
int main()
|
||||
|
|
101
libstdc++-v3/testsuite/std/time/weekday/io.cc
Normal file
101
libstdc++-v3/testsuite/std/time/weekday/io.cc
Normal file
|
@ -0,0 +1,101 @@
|
|||
// { dg-options "-std=gnu++20" }
|
||||
// { dg-do run { target c++20 } }
|
||||
// { dg-require-namedlocale "fr_FR.ISO8859-15" }
|
||||
|
||||
#include <chrono>
|
||||
#include <sstream>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
void
|
||||
test_ostream()
|
||||
{
|
||||
using std::ostringstream;
|
||||
using namespace std::chrono;
|
||||
|
||||
ostringstream ss;
|
||||
for (int i = 0; i <= 7; ++i)
|
||||
ss << weekday(i);
|
||||
VERIFY( ss.str() == "SunMonTueWedThuFriSatSun" );
|
||||
ss.str("");
|
||||
ss << weekday(8) << '|' << weekday(99);
|
||||
VERIFY( ss.str() == "8 is not a valid weekday|99 is not a valid weekday" );
|
||||
|
||||
ss.str("");
|
||||
ss.imbue(std::locale(ISO_8859(15,fr_FR)));
|
||||
ss << weekday(6);
|
||||
VERIFY( ss.str() == "sam." );
|
||||
}
|
||||
|
||||
void
|
||||
test_format()
|
||||
{
|
||||
using std::chrono::weekday;
|
||||
|
||||
auto s = std::format("{:%a%%%A%t%u%n%w}", std::chrono::Monday);
|
||||
VERIFY( s == "Mon%Monday\t1\n1" );
|
||||
auto ws = std::format(L"{:%a%%%A%t%u%n%w}", weekday(7));
|
||||
VERIFY( ws == L"Sun%Sunday\t7\n0" );
|
||||
|
||||
s = std::format("{:%w}", weekday(8));
|
||||
VERIFY( s == "8" );
|
||||
|
||||
try
|
||||
{
|
||||
(void) std::format("{:%a}", weekday(8));
|
||||
VERIFY(false);
|
||||
}
|
||||
catch (const std::format_error&)
|
||||
{
|
||||
}
|
||||
|
||||
s = std::format("{} is OK, but {:L}", weekday(2), weekday(13));
|
||||
VERIFY( s == "Tue is OK, but 13 is not a valid weekday" );
|
||||
|
||||
std::locale loc_fr(ISO_8859(15,fr_FR));
|
||||
|
||||
s = std::format("{:%Ow}", weekday(1));
|
||||
VERIFY( s == "1" );
|
||||
s = std::format(std::locale::classic(), "{:%Ow}", weekday(1));
|
||||
VERIFY( s == "1" );
|
||||
s = std::format(std::locale::classic(), "{:L%Ow}", weekday(1));
|
||||
VERIFY( s == "1" );
|
||||
s = std::format(loc_fr, "{:%Ow}", weekday(1));
|
||||
VERIFY( s == "1" );
|
||||
s = std::format(loc_fr, "{:L%Ow}", weekday(1));
|
||||
VERIFY( s == "1" );
|
||||
// TODO test "{:L%Ow}" with locale that has alternative numeric rep.
|
||||
|
||||
s = std::format(loc_fr, "{:%a}", weekday(1));
|
||||
VERIFY( s == "Mon" );
|
||||
s = std::format(loc_fr, "{:L%a}", weekday(1));
|
||||
VERIFY( s == "lun." );
|
||||
|
||||
std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
|
||||
std::string_view my_specs = "aAuw";
|
||||
for (char c : specs)
|
||||
{
|
||||
char fmt[] = { '{', ':', '%', c, '}' };
|
||||
try
|
||||
{
|
||||
(void) std::vformat(std::string_view(fmt, 5),
|
||||
std::make_format_args(weekday(1)));
|
||||
// The call above should throw for any conversion-spec not in my_specs:
|
||||
VERIFY(my_specs.find(c) != my_specs.npos);
|
||||
}
|
||||
catch (const std::format_error& e)
|
||||
{
|
||||
VERIFY(my_specs.find(c) == my_specs.npos);
|
||||
std::string_view s = e.what();
|
||||
// Libstdc++-specific message:
|
||||
VERIFY(s.find("format argument does not contain the information "
|
||||
"required by the chrono-specs") != s.npos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_ostream();
|
||||
test_format();
|
||||
// TODO: test_parse();
|
||||
}
|
89
libstdc++-v3/testsuite/std/time/year/io.cc
Normal file
89
libstdc++-v3/testsuite/std/time/year/io.cc
Normal file
|
@ -0,0 +1,89 @@
|
|||
// { dg-options "-std=gnu++20" }
|
||||
// { dg-do run { target c++20 } }
|
||||
// { dg-require-namedlocale "fr_FR.ISO8859-15" }
|
||||
|
||||
#include <chrono>
|
||||
#include <sstream>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
void
|
||||
test_ostream()
|
||||
{
|
||||
using std::ostringstream;
|
||||
using namespace std::chrono;
|
||||
|
||||
ostringstream ss;
|
||||
for (int y : {-1234, -44, -1, 0, 5, 32, 325, 1066, 2022})
|
||||
ss << year(y) << ' ';
|
||||
VERIFY( ss.str() == "-1234 -0044 -0001 0000 0005 0032 0325 1066 2022 " );
|
||||
ss.str("");
|
||||
ss << year::min() << ' ' << year::max() << ' ' << --year::min();
|
||||
VERIFY( ss.str() == "-32767 32767 -32768 is not a valid year" );
|
||||
|
||||
ss.str("");
|
||||
ss.imbue(std::locale(ISO_8859(15,fr_FR)));
|
||||
ss << 1789y;
|
||||
VERIFY( ss.str() == "1789" );
|
||||
}
|
||||
|
||||
void
|
||||
test_format()
|
||||
{
|
||||
using std::chrono::year;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
auto s = std::format("{:%y%%%Y%t%C%n}", 2022y);
|
||||
VERIFY( s == "22%2022\t20\n" );
|
||||
auto ws = std::format(L"{:%y%%%Y%t%C%n}", 2023y);
|
||||
VERIFY( ws == L"23%2023\t20\n" );
|
||||
|
||||
s = std::format("{:%Y}", --year::min());
|
||||
VERIFY( s == "-32768" );
|
||||
|
||||
s = std::format("{}", --year::min()); // formatted via ostream
|
||||
VERIFY( s == "-32768 is not a valid year" );
|
||||
|
||||
s = std::format("{:%y} {:%y}", 1976y, -1976y);
|
||||
VERIFY( s == "76 76" ); // LWG 3831
|
||||
|
||||
s = std::format("{0:%EC}{0:%Ey} = {0:%EY}", 1642y);
|
||||
VERIFY( s == "1642 = 1642" );
|
||||
s = std::format("{0:L%EC}{0:L%Ey} = {0:L%EY}", 1642y);
|
||||
VERIFY( s == "1642 = 1642" );
|
||||
s = std::format(std::locale::classic(), "{0:L%EC}{0:L%Ey} = {0:L%EY}", 1642y);
|
||||
VERIFY( s == "1642 = 1642" );
|
||||
|
||||
// TODO test "{:L%EC}" with locale that has alternative era rep.
|
||||
// TODO test "{:L%Ey}" with locale that has alternative year rep.
|
||||
// TODO test "{:L%EY}" with locale that has alternative year rep.
|
||||
// TODO test "{:L%Oy}" with locale that has alternative numeric rep.
|
||||
|
||||
std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
|
||||
std::string_view my_specs = "CyY";
|
||||
for (char c : specs)
|
||||
{
|
||||
char fmt[] = { '{', ':', '%', c, '}' };
|
||||
try
|
||||
{
|
||||
(void) std::vformat(std::string_view(fmt, 5),
|
||||
std::make_format_args(year(2022)));
|
||||
// The call above should throw for any conversion-spec not in my_specs:
|
||||
VERIFY(my_specs.find(c) != my_specs.npos);
|
||||
}
|
||||
catch (const std::format_error& e)
|
||||
{
|
||||
VERIFY(my_specs.find(c) == my_specs.npos);
|
||||
std::string_view s = e.what();
|
||||
// Libstdc++-specific message:
|
||||
VERIFY(s.find("format argument does not contain the information "
|
||||
"required by the chrono-specs") != s.npos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_ostream();
|
||||
test_format();
|
||||
// TODO: test_parse();
|
||||
}
|
121
libstdc++-v3/testsuite/std/time/year_month_day/io.cc
Normal file
121
libstdc++-v3/testsuite/std/time/year_month_day/io.cc
Normal file
|
@ -0,0 +1,121 @@
|
|||
// { dg-options "-std=gnu++20" }
|
||||
// { dg-do run { target c++20 } }
|
||||
// { dg-require-namedlocale "fr_FR.ISO8859-15" }
|
||||
|
||||
#include <chrono>
|
||||
#include <sstream>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
void
|
||||
test_ostream()
|
||||
{
|
||||
using std::ostringstream;
|
||||
using namespace std::chrono;
|
||||
|
||||
ostringstream ss;
|
||||
ss << 2022y/December/19 << ' ' << 2022y/November/31;
|
||||
VERIFY( ss.str() == "2022-12-19 2022-11-31 is not a valid date" );
|
||||
|
||||
ss.str("");
|
||||
ss.imbue(std::locale(ISO_8859(15,fr_FR)));
|
||||
ss << 1789y/July/14;
|
||||
VERIFY( ss.str() == "1789-07-14" );
|
||||
}
|
||||
|
||||
void
|
||||
test_format()
|
||||
{
|
||||
using std::chrono::year_month_day;
|
||||
using std::chrono::December;
|
||||
using std::chrono::January;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
auto s = std::format("{:%y%%%Y%t%C%n%j %a %b}", 2022y/December/19);
|
||||
VERIFY( s == "22%2022\t20\n353 Mon Dec" );
|
||||
auto ws = std::format(L"{:%y%%%Y%t%C%n%d}", 2023y/January/32);
|
||||
VERIFY( ws == L"23%2023\t20\n32" );
|
||||
|
||||
s = std::format("{:%F} {}", 2023y/January/32, 2023y/January/32);
|
||||
VERIFY( s == "2023-01-32 2023-01-32 is not a valid date" );
|
||||
|
||||
s = std::format("{:%C%g-W%V-%u}", 2022y/January/1);
|
||||
VERIFY( s == "2021-W52-6" );
|
||||
s = std::format("{:%G-W%V-%u}", 2022y/January/3);
|
||||
VERIFY( s == "2022-W01-1" );
|
||||
|
||||
// %U: Week number for weeks starting on Sunday
|
||||
s = std::format("Day {:%w (%a) of Week %U of %Y}", 2022y/January/1);
|
||||
VERIFY( s == "Day 6 (Sat) of Week 00 of 2022" );
|
||||
s = std::format("Day {:%w (%a) of Week %U of %Y}", 2022y/January/2);
|
||||
VERIFY( s == "Day 0 (Sun) of Week 01 of 2022" );
|
||||
// %W: Week number for weeks starting on Monday
|
||||
s = std::format("Day {:%u (%a) of Week %W of %Y}", 2022y/January/2);
|
||||
VERIFY( s == "Day 7 (Sun) of Week 00 of 2022" );
|
||||
s = std::format("Day {:%u (%a) of Week %W of %Y}", 2022y/January/3);
|
||||
VERIFY( s == "Day 1 (Mon) of Week 01 of 2022" );
|
||||
|
||||
// %V: ISO week number (ISO 8601).
|
||||
s = std::format("W{:%V}", 1977y/1/1);
|
||||
VERIFY( s == "W53" );
|
||||
s = std::format("W{:%V}", 1977y/1/2);
|
||||
VERIFY( s == "W53" );
|
||||
s = std::format("W{:%V}", 1977y/12/31);
|
||||
VERIFY( s == "W52" );
|
||||
s = std::format("W{:%V}", 1978y/1/1);
|
||||
VERIFY( s == "W52" );
|
||||
s = std::format("W{:%V}", 1978y/1/2);
|
||||
VERIFY( s == "W01" );
|
||||
s = std::format("W{:%V}", 1978y/12/31);
|
||||
VERIFY( s == "W52" );
|
||||
s = std::format("W{:%V}", 1979y/1/1);
|
||||
VERIFY( s == "W01" );
|
||||
s = std::format("W{:%V}", 1979y/12/30);
|
||||
VERIFY( s == "W52" );
|
||||
s = std::format("W{:%V}", 1979y/12/31);
|
||||
VERIFY( s == "W01" );
|
||||
s = std::format("W{:%V}", 1980y/1/1);
|
||||
VERIFY( s == "W01" );
|
||||
|
||||
s = std::format("{:%x}", 2022y/December/19);
|
||||
VERIFY( s == "12/19/22" );
|
||||
s = std::format("{:L%x}", 2022y/December/19);
|
||||
VERIFY( s == "12/19/22" );
|
||||
std::locale loc_fr(ISO_8859(15,fr_FR));
|
||||
s = std::format(loc_fr, "{:%x}", 2022y/December/19);
|
||||
VERIFY( s == "12/19/22" );
|
||||
s = std::format(loc_fr, "{:L%x}", 2022y/December/19);
|
||||
VERIFY( s == "19/12/2022" );
|
||||
s = std::format(loc_fr, "{}", 2022y/December/19);
|
||||
VERIFY( s == "2022-12-19" );
|
||||
s = std::format(loc_fr, "{:L%F}", 2022y/December/19);
|
||||
VERIFY( s == "2022-12-19" );
|
||||
|
||||
std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
|
||||
std::string_view my_specs = "aAbBCdDeFgGhjmuUVwWxyY";
|
||||
for (char c : specs)
|
||||
{
|
||||
char fmt[] = { '{', ':', '%', c, '}' };
|
||||
try
|
||||
{
|
||||
(void) std::vformat(std::string_view(fmt, 5),
|
||||
std::make_format_args(2022y/December/19));
|
||||
// The call above should throw for any conversion-spec not in my_specs:
|
||||
VERIFY(my_specs.find(c) != my_specs.npos);
|
||||
}
|
||||
catch (const std::format_error& e)
|
||||
{
|
||||
VERIFY(my_specs.find(c) == my_specs.npos);
|
||||
std::string_view s = e.what();
|
||||
// Libstdc++-specific message:
|
||||
VERIFY(s.find("format argument does not contain the information "
|
||||
"required by the chrono-specs") != s.npos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_ostream();
|
||||
test_format();
|
||||
// TODO: test_parse();
|
||||
}
|
Loading…
Add table
Reference in a new issue