forked from OSchip/llvm-project
[libc++][chrono] Implements formatter year.
Partially implements: - P1361 Integration of chrono with text formatting Reviewed By: ldionne, #libc Differential Revision: https://reviews.llvm.org/D133663
This commit is contained in:
parent
d7c85d7e34
commit
3eb4f16b44
|
@ -10,7 +10,7 @@ Section,Description,Dependencies,Assignee,Status,First released version
|
|||
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::local-time-format-t<Duration>``",A ``<chrono>`` implementation,Not assigned,,,
|
||||
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::day``",,Mark de Wever,|Complete|, Clang 16
|
||||
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::month``",,Mark de Wever,|In Progress|,
|
||||
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::year``",,Mark de Wever,|In Progress|,
|
||||
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::year``",,Mark de Wever,|Complete|, Clang 16
|
||||
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::weekday``",,Mark de Wever,|In Progress|,
|
||||
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::weekday_indexed``",,Mark de Wever,|In Progress|,
|
||||
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::weekday_last``",,Mark de Wever,|In Progress|,
|
||||
|
|
Can't render this file because it has a wrong number of fields in line 2.
|
|
@ -11,6 +11,7 @@
|
|||
#define _LIBCPP___CHRONO_CONVERT_TO_TM_H
|
||||
|
||||
#include <__chrono/day.h>
|
||||
#include <__chrono/year.h>
|
||||
#include <__concepts/same_as.h>
|
||||
#include <__config>
|
||||
|
||||
|
@ -33,6 +34,8 @@ _LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(const _ChronoCalendarTimePoint& __valu
|
|||
|
||||
if constexpr (same_as<_ChronoCalendarTimePoint, chrono::day>)
|
||||
__result.tm_mday = static_cast<unsigned>(__value);
|
||||
else if constexpr (same_as<_ChronoCalendarTimePoint, chrono::year>)
|
||||
__result.tm_year = static_cast<int>(__value) - 1900;
|
||||
else
|
||||
static_assert(sizeof(_ChronoCalendarTimePoint) == 0, "Add the missing type specialization");
|
||||
|
||||
|
|
|
@ -13,12 +13,17 @@
|
|||
#include <__chrono/convert_to_tm.h>
|
||||
#include <__chrono/day.h>
|
||||
#include <__chrono/parser_std_format_spec.h>
|
||||
#include <__chrono/statically_widen.h>
|
||||
#include <__chrono/year.h>
|
||||
#include <__config>
|
||||
#include <__format/concepts.h>
|
||||
#include <__format/format_functions.h>
|
||||
#include <__format/format_parse_context.h>
|
||||
#include <__format/formatter.h>
|
||||
#include <__format/formatter_output.h>
|
||||
#include <__format/parser_std_format_spec.h>
|
||||
#include <__memory/addressof.h>
|
||||
#include <cmath>
|
||||
#include <ctime>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
@ -52,6 +57,34 @@ namespace __formatter {
|
|||
///
|
||||
/// When no chrono-specs are provided it uses the stream formatter.
|
||||
|
||||
template <class _CharT>
|
||||
_LIBCPP_HIDE_FROM_ABI void __format_year(int __year, basic_stringstream<_CharT>& __sstr) {
|
||||
if (__year < 0) {
|
||||
__sstr << _CharT('-');
|
||||
__year = -__year;
|
||||
}
|
||||
|
||||
// TODO FMT Write an issue
|
||||
// If the result has less than four digits it is zero-padded with 0 to two digits.
|
||||
// is less -> has less
|
||||
// left-padded -> zero-padded, otherwise the proper value would be 000-0.
|
||||
|
||||
// Note according to the wording it should be left padded, which is odd.
|
||||
__sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:04}"), __year);
|
||||
}
|
||||
|
||||
template <class _CharT>
|
||||
_LIBCPP_HIDE_FROM_ABI void __format_century(int __year, basic_stringstream<_CharT>& __sstr) {
|
||||
// TODO FMT Write an issue
|
||||
// [tab:time.format.spec]
|
||||
// %C The year divided by 100 using floored division. If the result is a
|
||||
// single decimal digit, it is prefixed with 0.
|
||||
|
||||
bool __negative = __year < 0;
|
||||
int __century = (__year - (99 * __negative)) / 100; // floored division
|
||||
__sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:02}"), __century);
|
||||
}
|
||||
|
||||
template <class _CharT, class _Tp>
|
||||
_LIBCPP_HIDE_FROM_ABI void __format_chrono_using_chrono_specs(
|
||||
const _Tp& __value, basic_stringstream<_CharT>& __sstr, basic_string_view<_CharT> __chrono_specs) {
|
||||
|
@ -74,7 +107,59 @@ _LIBCPP_HIDE_FROM_ABI void __format_chrono_using_chrono_specs(
|
|||
__sstr << *__it;
|
||||
break;
|
||||
|
||||
case _CharT('C'): {
|
||||
// strftime's output is only defined in the range [00, 99].
|
||||
int __year = __t.tm_year + 1900;
|
||||
if (__year < 1000 || __year > 9999)
|
||||
__formatter::__format_century(__year, __sstr);
|
||||
else
|
||||
__facet.put({__sstr}, __sstr, _CharT(' '), std::addressof(__t), __s, __it + 1);
|
||||
} break;
|
||||
|
||||
// Unlike time_put and strftime the formatting library requires %Y
|
||||
//
|
||||
// [tab:time.format.spec]
|
||||
// The year as a decimal number. If the result is less than four digits
|
||||
// it is left-padded with 0 to four digits.
|
||||
//
|
||||
// This means years in the range (-1000, 1000) need manual formatting.
|
||||
// It's unclear whether %EY needs the same treatment. For example the
|
||||
// Japanese EY contains the era name and year. This is zero-padded to 2
|
||||
// digits in time_put (note that older glibc versions didn't do
|
||||
// padding.) However most eras won't reach 100 years, let alone 1000.
|
||||
// So padding to 4 digits seems unwanted for Japanese.
|
||||
//
|
||||
// The same applies to %Ex since that too depends on the era.
|
||||
//
|
||||
// %x the locale's date representation is currently doesn't handle the
|
||||
// zero-padding too.
|
||||
//
|
||||
// The 4 digits can be implemented better at a later time. On POSIX
|
||||
// systems the required information can be extracted by nl_langinfo
|
||||
// https://man7.org/linux/man-pages/man3/nl_langinfo.3.html
|
||||
//
|
||||
// Note since year < -1000 is expected to be rare it uses the more
|
||||
// expensive year routine.
|
||||
//
|
||||
// TODO FMT evaluate the comment above.
|
||||
|
||||
# if defined(__GLIBC__) || defined(_AIX)
|
||||
case _CharT('y'):
|
||||
// Glibc fails for negative values, AIX for positive values too.
|
||||
__sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:02}"), (std::abs(__t.tm_year + 1900)) % 100);
|
||||
break;
|
||||
# endif // defined(__GLIBC__) || defined(_AIX)
|
||||
|
||||
case _CharT('Y'): {
|
||||
int __year = __t.tm_year + 1900;
|
||||
if (__year < 1000)
|
||||
__formatter::__format_year(__year, __sstr);
|
||||
else
|
||||
__facet.put({__sstr}, __sstr, _CharT(' '), std::addressof(__t), __s, __it + 1);
|
||||
} break;
|
||||
|
||||
case _CharT('O'):
|
||||
case _CharT('E'):
|
||||
++__it;
|
||||
[[fallthrough]];
|
||||
default:
|
||||
|
@ -146,7 +231,19 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
#endif //if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)
|
||||
template <__fmt_char_type _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<chrono::year, _CharT>
|
||||
: public __formatter_chrono<_CharT> {
|
||||
public:
|
||||
using _Base = __formatter_chrono<_CharT>;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx)
|
||||
-> decltype(__parse_ctx.begin()) {
|
||||
return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__year);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include <__chrono/day.h>
|
||||
#include <__chrono/statically_widen.h>
|
||||
#include <__chrono/year.h>
|
||||
#include <__config>
|
||||
#include <__format/format_functions.h>
|
||||
#include <ostream>
|
||||
|
@ -40,6 +41,13 @@ operator<<(basic_ostream<_CharT, _Traits>& __os, const day& __d) {
|
|||
: std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:02} is not a valid day"), static_cast<unsigned>(__d)));
|
||||
}
|
||||
|
||||
template <class _CharT, class _Traits>
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT basic_ostream<_CharT, _Traits>&
|
||||
operator<<(basic_ostream<_CharT, _Traits>& __os, const year& __y) {
|
||||
return __os << (__y.ok() ? std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:%Y}"), __y)
|
||||
: std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:%Y} is not a valid year"), __y));
|
||||
}
|
||||
|
||||
} // namespace chrono
|
||||
|
||||
#endif //if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)
|
||||
|
|
|
@ -355,6 +355,9 @@ constexpr year operator+(const year& x, const years& y) noexcept;
|
|||
constexpr year operator+(const years& x, const year& y) noexcept;
|
||||
constexpr year operator-(const year& x, const years& y) noexcept;
|
||||
constexpr years operator-(const year& x, const year& y) noexcept;
|
||||
template<class charT, class traits>
|
||||
basic_ostream<charT, traits>&
|
||||
operator<<(basic_ostream<charT, traits>& os, const year& y);
|
||||
|
||||
// 25.8.6, class weekday // C++20
|
||||
class weekday;
|
||||
|
@ -620,6 +623,7 @@ bool operator>=(const time_zone& x, const time_zone& y) noexcept;
|
|||
|
||||
namespace std {
|
||||
template<class charT> struct formatter<chrono::day, charT>; // C++20
|
||||
template<class charT> struct formatter<chrono::year, charT>; // C++20
|
||||
} // namespace std
|
||||
|
||||
namespace chrono {
|
||||
|
|
|
@ -106,6 +106,7 @@ charconv type_traits
|
|||
chrono array
|
||||
chrono bit
|
||||
chrono charconv
|
||||
chrono cmath
|
||||
chrono compare
|
||||
chrono concepts
|
||||
chrono cstddef
|
||||
|
|
|
|
@ -86,6 +86,7 @@ charconv type_traits
|
|||
chrono array
|
||||
chrono bit
|
||||
chrono charconv
|
||||
chrono cmath
|
||||
chrono compare
|
||||
chrono concepts
|
||||
chrono cstddef
|
||||
|
|
|
|
@ -143,7 +143,7 @@ void test_P1361() {
|
|||
|
||||
assert_is_formattable<std::chrono::day, CharT>();
|
||||
assert_is_not_formattable<std::chrono::month, CharT>();
|
||||
assert_is_not_formattable<std::chrono::year, CharT>();
|
||||
assert_is_formattable<std::chrono::year, CharT>();
|
||||
|
||||
assert_is_not_formattable<std::chrono::weekday, CharT>();
|
||||
assert_is_not_formattable<std::chrono::weekday_indexed, CharT>();
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: no-localization
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-format
|
||||
|
||||
// TODO FMT Investigate Windows issues.
|
||||
// UNSUPPORTED: msvc, target={{.+}}-windows-gnu
|
||||
|
||||
// REQUIRES: locale.fr_FR.UTF-8
|
||||
// REQUIRES: locale.ja_JP.UTF-8
|
||||
|
||||
// <chrono>
|
||||
// class year;
|
||||
|
||||
// template<class charT, class traits>
|
||||
// basic_ostream<charT, traits>&
|
||||
// operator<<(basic_ostream<charT, traits>& os, const year& year);
|
||||
|
||||
#include <chrono>
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
|
||||
#include "make_string.h"
|
||||
#include "platform_support.h" // locale name macros
|
||||
#include "test_macros.h"
|
||||
|
||||
#define SV(S) MAKE_STRING_VIEW(CharT, S)
|
||||
|
||||
template <class CharT>
|
||||
static std::basic_string<CharT> stream_c_locale(std::chrono::year year) {
|
||||
std::basic_stringstream<CharT> sstr;
|
||||
sstr << year;
|
||||
return sstr.str();
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
static std::basic_string<CharT> stream_fr_FR_locale(std::chrono::year year) {
|
||||
std::basic_stringstream<CharT> sstr;
|
||||
const std::locale locale(LOCALE_fr_FR_UTF_8);
|
||||
sstr.imbue(locale);
|
||||
sstr << year;
|
||||
return sstr.str();
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
static std::basic_string<CharT> stream_ja_JP_locale(std::chrono::year year) {
|
||||
std::basic_stringstream<CharT> sstr;
|
||||
const std::locale locale(LOCALE_ja_JP_UTF_8);
|
||||
sstr.imbue(locale);
|
||||
sstr << year;
|
||||
return sstr.str();
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
static void test() {
|
||||
assert(stream_c_locale<CharT>(std::chrono::year{-32'768}) == SV("-32768 is not a valid year"));
|
||||
assert(stream_c_locale<CharT>(std::chrono::year{-32'767}) == SV("-32767"));
|
||||
assert(stream_c_locale<CharT>(std::chrono::year{0}) == SV("0000"));
|
||||
assert(stream_c_locale<CharT>(std::chrono::year{1970}) == SV("1970"));
|
||||
assert(stream_c_locale<CharT>(std::chrono::year{32'767}) == SV("32767"));
|
||||
|
||||
assert(stream_fr_FR_locale<CharT>(std::chrono::year{-32'768}) == SV("-32768 is not a valid year"));
|
||||
assert(stream_fr_FR_locale<CharT>(std::chrono::year{-32'767}) == SV("-32767"));
|
||||
assert(stream_fr_FR_locale<CharT>(std::chrono::year{0}) == SV("0000"));
|
||||
assert(stream_fr_FR_locale<CharT>(std::chrono::year{1970}) == SV("1970"));
|
||||
assert(stream_fr_FR_locale<CharT>(std::chrono::year{32'767}) == SV("32767"));
|
||||
|
||||
assert(stream_ja_JP_locale<CharT>(std::chrono::year{-32'768}) == SV("-32768 is not a valid year"));
|
||||
assert(stream_ja_JP_locale<CharT>(std::chrono::year{-32'767}) == SV("-32767"));
|
||||
assert(stream_ja_JP_locale<CharT>(std::chrono::year{0}) == SV("0000"));
|
||||
assert(stream_ja_JP_locale<CharT>(std::chrono::year{1970}) == SV("1970"));
|
||||
assert(stream_ja_JP_locale<CharT>(std::chrono::year{32'767}) == SV("32767"));
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test<char>();
|
||||
|
||||
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
|
||||
test<wchar_t>();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,308 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: no-localization
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-format
|
||||
|
||||
// TODO FMT Investigate Windows issues.
|
||||
// UNSUPPORTED: msvc, target={{.+}}-windows-gnu
|
||||
|
||||
// REQUIRES: locale.fr_FR.UTF-8
|
||||
// REQUIRES: locale.ja_JP.UTF-8
|
||||
|
||||
// <chrono>
|
||||
|
||||
// template<class charT> struct formatter<chrono::year, charT>;
|
||||
|
||||
#include <chrono>
|
||||
#include <format>
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <locale>
|
||||
#include <iostream>
|
||||
#include <type_traits>
|
||||
|
||||
#include "formatter_tests.h"
|
||||
#include "make_string.h"
|
||||
#include "platform_support.h" // locale name macros
|
||||
#include "string_literal.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class CharT>
|
||||
static void test_no_chrono_specs() {
|
||||
check(SV("-32767"), SV("{}"), std::chrono::year{-32'767});
|
||||
check(SV("-1000"), SV("{}"), std::chrono::year{-1000});
|
||||
check(SV("-0100"), SV("{}"), std::chrono::year{-100});
|
||||
check(SV("-0010"), SV("{}"), std::chrono::year{-10});
|
||||
check(SV("-0001"), SV("{}"), std::chrono::year{-1});
|
||||
check(SV("0000"), SV("{}"), std::chrono::year{0});
|
||||
check(SV("0001"), SV("{}"), std::chrono::year{1});
|
||||
check(SV("0010"), SV("{}"), std::chrono::year{10});
|
||||
check(SV("0100"), SV("{}"), std::chrono::year{100});
|
||||
check(SV("1000"), SV("{}"), std::chrono::year{1000});
|
||||
check(SV("32727"), SV("{}"), std::chrono::year{32'727});
|
||||
|
||||
// Invalid year
|
||||
check(SV("-32768 is not a valid year"), SV("{}"), std::chrono::year{-32'768});
|
||||
check(SV("-32768 is not a valid year"), SV("{}"), std::chrono::year{32'768});
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
static void test_valid_values() {
|
||||
constexpr std::basic_string_view<CharT> fmt = SV(
|
||||
"{:"
|
||||
"%%C='%C'%t"
|
||||
"%%EC='%EC'%t"
|
||||
"%%y='%y'%t"
|
||||
"%%Ey='%Ey'%t"
|
||||
"%%Oy='%Oy'%t"
|
||||
"%%Y='%Y'%t"
|
||||
"%%EY='%EY'%t"
|
||||
"%n}");
|
||||
constexpr std::basic_string_view<CharT> lfmt = SV(
|
||||
"{:L"
|
||||
"%%C='%C'%t"
|
||||
"%%EC='%EC'%t"
|
||||
"%%y='%y'%t"
|
||||
"%%Ey='%Ey'%t"
|
||||
"%%Oy='%Oy'%t"
|
||||
"%%Y='%Y'%t"
|
||||
"%%EY='%EY'%t"
|
||||
"%n}");
|
||||
|
||||
const std::locale loc(LOCALE_ja_JP_UTF_8);
|
||||
std::locale::global(std::locale(LOCALE_fr_FR_UTF_8));
|
||||
|
||||
// Non localized output using C-locale
|
||||
check(SV("%C='00'\t"
|
||||
#if defined(__APPLE__)
|
||||
"%EC='00'\t"
|
||||
#else
|
||||
"%EC='0'\t"
|
||||
#endif
|
||||
"%y='00'\t"
|
||||
"%Ey='00'\t"
|
||||
"%Oy='00'\t"
|
||||
"%Y='0000'\t"
|
||||
#if defined(__APPLE__)
|
||||
"%EY='0000'\t"
|
||||
#elif defined(_AIX)
|
||||
"%EY=''\t"
|
||||
#else
|
||||
"%EY='0'\t"
|
||||
#endif
|
||||
"\n"),
|
||||
fmt,
|
||||
std::chrono::year{0});
|
||||
|
||||
check(SV("%C='19'\t"
|
||||
"%EC='19'\t"
|
||||
"%y='70'\t"
|
||||
"%Ey='70'\t"
|
||||
"%Oy='70'\t"
|
||||
"%Y='1970'\t"
|
||||
"%EY='1970'\t"
|
||||
"\n"),
|
||||
fmt,
|
||||
std::chrono::year{1970});
|
||||
|
||||
check(SV("%C='20'\t"
|
||||
"%EC='20'\t"
|
||||
"%y='38'\t"
|
||||
"%Ey='38'\t"
|
||||
"%Oy='38'\t"
|
||||
"%Y='2038'\t"
|
||||
"%EY='2038'\t"
|
||||
"\n"),
|
||||
fmt,
|
||||
std::chrono::year{2038});
|
||||
|
||||
// Use the global locale (fr_FR)
|
||||
check(SV("%C='00'\t"
|
||||
#if defined(__APPLE__)
|
||||
"%EC='00'\t"
|
||||
#else
|
||||
"%EC='0'\t"
|
||||
#endif
|
||||
"%y='00'\t"
|
||||
"%Ey='00'\t"
|
||||
"%Oy='00'\t"
|
||||
"%Y='0000'\t"
|
||||
#if defined(__APPLE__)
|
||||
"%EY='0000'\t"
|
||||
#elif defined(_AIX)
|
||||
"%EY=''\t"
|
||||
#else
|
||||
"%EY='0'\t"
|
||||
#endif
|
||||
"\n"),
|
||||
lfmt,
|
||||
std::chrono::year{0});
|
||||
|
||||
check(SV("%C='19'\t"
|
||||
"%EC='19'\t"
|
||||
"%y='70'\t"
|
||||
"%Ey='70'\t"
|
||||
"%Oy='70'\t"
|
||||
"%Y='1970'\t"
|
||||
"%EY='1970'\t"
|
||||
"\n"),
|
||||
lfmt,
|
||||
std::chrono::year{1970});
|
||||
|
||||
check(SV("%C='20'\t"
|
||||
"%EC='20'\t"
|
||||
"%y='38'\t"
|
||||
"%Ey='38'\t"
|
||||
"%Oy='38'\t"
|
||||
"%Y='2038'\t"
|
||||
"%EY='2038'\t"
|
||||
"\n"),
|
||||
lfmt,
|
||||
std::chrono::year{2038});
|
||||
|
||||
// Use supplied locale (ja_JP). This locale has a different alternate.
|
||||
#if defined(__APPLE__) || defined(_AIX)
|
||||
|
||||
check(SV("%C='00'\t"
|
||||
# if defined(__APPLE__)
|
||||
"%EC='00'\t"
|
||||
# else
|
||||
"%EC='0'\t"
|
||||
# endif
|
||||
"%y='00'\t"
|
||||
"%Ey='00'\t"
|
||||
"%Oy='00'\t"
|
||||
"%Y='0000'\t"
|
||||
# if defined(_AIX)
|
||||
"%EY=''\t"
|
||||
# else
|
||||
"%EY='0000'\t"
|
||||
# endif
|
||||
"\n"),
|
||||
lfmt,
|
||||
std::chrono::year{0});
|
||||
|
||||
check(SV("%C='19'\t"
|
||||
"%EC='19'\t"
|
||||
"%y='70'\t"
|
||||
"%Ey='70'\t"
|
||||
"%Oy='70'\t"
|
||||
"%Y='1970'\t"
|
||||
"%EY='1970'\t"
|
||||
"\n"),
|
||||
lfmt,
|
||||
std::chrono::year{1970});
|
||||
|
||||
check(SV("%C='20'\t"
|
||||
"%EC='20'\t"
|
||||
"%y='38'\t"
|
||||
"%Ey='38'\t"
|
||||
"%Oy='38'\t"
|
||||
"%Y='2038'\t"
|
||||
"%EY='2038'\t"
|
||||
"\n"),
|
||||
lfmt,
|
||||
std::chrono::year{2038});
|
||||
|
||||
#else // defined(__APPLE__) || defined(_AIX)
|
||||
check(loc,
|
||||
SV("%C='00'\t"
|
||||
"%EC='紀元前'\t"
|
||||
"%y='00'\t"
|
||||
// https://sourceware.org/bugzilla/show_bug.cgi?id=23758
|
||||
# if defined(__GLIBC__) && __GLIBC__ <= 2 && __GLIBC_MINOR__ < 29
|
||||
"%Ey='1'\t"
|
||||
# else
|
||||
"%Ey='01'\t"
|
||||
# endif
|
||||
"%Oy='〇'\t"
|
||||
"%Y='0000'\t"
|
||||
// https://sourceware.org/bugzilla/show_bug.cgi?id=23758
|
||||
# if defined(__GLIBC__) && __GLIBC__ <= 2 && __GLIBC_MINOR__ < 29
|
||||
"%EY='紀元前1年'\t"
|
||||
# else
|
||||
"%EY='紀元前01年'\t"
|
||||
# endif
|
||||
"\n"),
|
||||
lfmt,
|
||||
std::chrono::year{0});
|
||||
|
||||
check(loc,
|
||||
SV("%C='19'\t"
|
||||
"%EC='昭和'\t"
|
||||
"%y='70'\t"
|
||||
"%Ey='45'\t"
|
||||
"%Oy='七十'\t"
|
||||
"%Y='1970'\t"
|
||||
"%EY='昭和45年'\t"
|
||||
"\n"),
|
||||
lfmt,
|
||||
std::chrono::year{1970});
|
||||
|
||||
// Note this test will fail if the Reiwa era ends before 2038.
|
||||
check(loc,
|
||||
SV("%C='20'\t"
|
||||
"%EC='令和'\t"
|
||||
"%y='38'\t"
|
||||
"%Ey='20'\t"
|
||||
"%Oy='三十八'\t"
|
||||
"%Y='2038'\t"
|
||||
"%EY='令和20年'\t"
|
||||
"\n"),
|
||||
lfmt,
|
||||
std::chrono::year{2038});
|
||||
#endif // defined(__APPLE__) || defined(_AIX)
|
||||
|
||||
std::locale::global(std::locale::classic());
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
static void test_padding() {
|
||||
constexpr std::basic_string_view<CharT> fmt = SV("{:%%C='%C'%t%%y='%y'%t%%Y='%Y'%t%n}");
|
||||
|
||||
check(SV("%C='-100'\t%y='99'\t%Y='-9999'\t\n"), fmt, std::chrono::year{-9'999});
|
||||
check(SV("%C='-10'\t%y='99'\t%Y='-0999'\t\n"), fmt, std::chrono::year{-999});
|
||||
check(SV("%C='-1'\t%y='99'\t%Y='-0099'\t\n"), fmt, std::chrono::year{-99});
|
||||
check(SV("%C='-1'\t%y='09'\t%Y='-0009'\t\n"), fmt, std::chrono::year{-9});
|
||||
check(SV("%C='00'\t%y='00'\t%Y='0000'\t\n"), fmt, std::chrono::year{0});
|
||||
check(SV("%C='00'\t%y='09'\t%Y='0009'\t\n"), fmt, std::chrono::year{9});
|
||||
check(SV("%C='00'\t%y='99'\t%Y='0099'\t\n"), fmt, std::chrono::year{99});
|
||||
check(SV("%C='09'\t%y='99'\t%Y='0999'\t\n"), fmt, std::chrono::year{999});
|
||||
check(SV("%C='99'\t%y='99'\t%Y='9999'\t\n"), fmt, std::chrono::year{9'999});
|
||||
check(SV("%C='100'\t%y='00'\t%Y='10000'\t\n"), fmt, std::chrono::year{10'000});
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
static void test() {
|
||||
test_no_chrono_specs<CharT>();
|
||||
test_valid_values<CharT>();
|
||||
test_padding<CharT>();
|
||||
check_invalid_types<CharT>(
|
||||
{SV("C"), SV("y"), SV("Y"), SV("EC"), SV("Ey"), SV("EY"), SV("Oy")}, std::chrono::year{1970});
|
||||
|
||||
check_exception("Expected '%' or '}' in the chrono format-string", SV("{:A"), std::chrono::year{1970});
|
||||
check_exception("The chrono-specs contains a '{'", SV("{:%%{"), std::chrono::year{1970});
|
||||
check_exception("End of input while parsing the modifier chrono conversion-spec", SV("{:%"), std::chrono::year{1970});
|
||||
check_exception("End of input while parsing the modifier E", SV("{:%E"), std::chrono::year{1970});
|
||||
check_exception("End of input while parsing the modifier O", SV("{:%O"), std::chrono::year{1970});
|
||||
|
||||
// Precision not allowed
|
||||
check_exception("Expected '%' or '}' in the chrono format-string", SV("{:.3}"), std::chrono::year{1970});
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test<char>();
|
||||
|
||||
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
|
||||
test<wchar_t>();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -185,7 +185,7 @@ void test_P1361() {
|
|||
|
||||
assert_formatter_is_enabled<std::chrono::day, CharT>();
|
||||
assert_formatter_is_disabled<std::chrono::month, CharT>();
|
||||
assert_formatter_is_disabled<std::chrono::year, CharT>();
|
||||
assert_formatter_is_enabled<std::chrono::year, CharT>();
|
||||
|
||||
assert_formatter_is_disabled<std::chrono::weekday, CharT>();
|
||||
assert_formatter_is_disabled<std::chrono::weekday_indexed, CharT>();
|
||||
|
|
|
@ -190,7 +190,7 @@ check-generated-output)
|
|||
! grep -rn '[^ -~]' libcxx/include libcxx/src libcxx/test libcxx/benchmarks \
|
||||
--exclude '*.dat' \
|
||||
--exclude 'format_tests.h' \
|
||||
--exclude 'formatter.day.pass.cpp' \
|
||||
--exclude 'formatter.*.pass.cpp' \
|
||||
--exclude 'grep.pass.cpp' \
|
||||
--exclude 'locale-specific_form.pass.cpp' \
|
||||
--exclude 'std_format_spec_string_unicode.bench.cpp' \
|
||||
|
|
Loading…
Reference in New Issue