xref: /llvm-project/libcxx/test/std/time/time.syn/formatter.year_month.pass.cpp (revision 6a54dfbfe534276d644d7f9c027f0deeb748dd53)
1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 // UNSUPPORTED: c++03, c++11, c++14, c++17
10 // UNSUPPORTED: no-localization
11 // UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
12 
13 // TODO FMT This test should not require std::to_chars(floating-point)
14 // XFAIL: availability-fp_to_chars-missing
15 
16 // REQUIRES: locale.fr_FR.UTF-8
17 // REQUIRES: locale.ja_JP.UTF-8
18 
19 // <chrono>
20 
21 // template<class charT> struct formatter<chrono::year_month, charT>;
22 
23 #include <chrono>
24 #include <format>
25 
26 #include <cassert>
27 #include <concepts>
28 #include <locale>
29 #include <iostream>
30 #include <type_traits>
31 
32 #include "formatter_tests.h"
33 #include "make_string.h"
34 #include "platform_support.h" // locale name macros
35 #include "string_literal.h"
36 #include "test_macros.h"
37 
38 template <class CharT>
39 static void test_no_chrono_specs() {
40   // Valid month
41   check(SV("1970/Jan"), SV("{}"), std::chrono::year_month{std::chrono::year{1970}, std::chrono::month{1}});
42   check(SV("*1970/Jan*"), SV("{:*^10}"), std::chrono::year_month{std::chrono::year{1970}, std::chrono::month{1}});
43   check(SV("*1970/Jan"), SV("{:*>9}"), std::chrono::year_month{std::chrono::year{1970}, std::chrono::month{1}});
44 
45   // Invalid month_day
46   check(SV("1970/0 is not a valid month"),
47         SV("{}"),
48         std::chrono::year_month{std::chrono::year{1970}, std::chrono::month{0}});
49   check(SV("*1970/0 is not a valid month*"),
50         SV("{:*^29}"),
51         std::chrono::year_month{std::chrono::year{1970}, std::chrono::month{0}});
52 }
53 
54 template <class CharT>
55 static void test_invalid_values() {
56   // Test that %b and %B throw an exception.
57   check_exception("Formatting a month name from an invalid month number",
58                   SV("{:%b}"),
59                   std::chrono::year_month{std::chrono::year{1970}, std::chrono::month{0}});
60 
61   check_exception("Formatting a month name from an invalid month number",
62                   SV("{:%B}"),
63                   std::chrono::year_month{std::chrono::year{1970}, std::chrono::month{0}});
64 }
65 
66 template <class CharT>
67 static void test_valid_values() {
68   constexpr std::basic_string_view<CharT> fmt = SV(
69       "{:"
70       "%%b='%b'%t"
71       "%%B='%B'%t"
72       "%%C='%C'%t"
73       "%%h='%h'%t"
74       "%%y='%y'%t"
75       "%%Y='%Y'%t"
76       "%%EC='%EC'%t"
77       "%%Ey='%Ey'%t"
78       "%%EY='%EY'%t"
79       "%%Oy='%Oy'%t"
80       "%n}");
81 
82   constexpr std::basic_string_view<CharT> lfmt = SV(
83       "{:L"
84       "%%b='%b'%t"
85       "%%B='%B'%t"
86       "%%C='%C'%t"
87       "%%h='%h'%t"
88       "%%y='%y'%t"
89       "%%Y='%Y'%t"
90       "%%EC='%EC'%t"
91       "%%Ey='%Ey'%t"
92       "%%EY='%EY'%t"
93       "%%Oy='%Oy'%t"
94       "%n}");
95 
96   const std::locale loc(LOCALE_ja_JP_UTF_8);
97   std::locale::global(std::locale(LOCALE_fr_FR_UTF_8));
98 
99   // Non localized output using C-locale
100   check(SV("%b='Jan'\t"
101            "%B='January'\t"
102            "%C='19'\t"
103            "%h='Jan'\t"
104            "%y='70'\t"
105            "%Y='1970'\t"
106            "%EC='19'\t"
107            "%Ey='70'\t"
108            "%EY='1970'\t"
109            "%Oy='70'\t"
110            "\n"),
111         fmt,
112         std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});
113 
114   check(SV("%b='May'\t"
115            "%B='May'\t"
116            "%C='20'\t"
117            "%h='May'\t"
118            "%y='04'\t"
119            "%Y='2004'\t"
120            "%EC='20'\t"
121            "%Ey='04'\t"
122            "%EY='2004'\t"
123            "%Oy='04'\t"
124            "\n"),
125         fmt,
126         std::chrono::year_month{std::chrono::year{2004}, std::chrono::May});
127 
128   // Use the global locale (fr_FR)
129   check(SV(
130 #if defined(__APPLE__)
131             "%b='jan'\t"
132 #else
133             "%b='janv.'\t"
134 #endif
135             "%B='janvier'\t"
136             "%C='19'\t"
137 #if defined(__APPLE__)
138             "%h='jan'\t"
139 #else
140             "%h='janv.'\t"
141 #endif
142             "%y='70'\t"
143             "%Y='1970'\t"
144             "%EC='19'\t"
145             "%Ey='70'\t"
146             "%EY='1970'\t"
147             "%Oy='70'\t"
148             "\n"),
149         lfmt,
150         std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});
151 
152   check(SV("%b='mai'\t"
153            "%B='mai'\t"
154            "%C='20'\t"
155            "%h='mai'\t"
156            "%y='04'\t"
157            "%Y='2004'\t"
158            "%EC='20'\t"
159            "%Ey='04'\t"
160            "%EY='2004'\t"
161            "%Oy='04'\t"
162            "\n"),
163         lfmt,
164         std::chrono::year_month{std::chrono::year{2004}, std::chrono::May});
165 
166   // Use supplied locale (ja_JP)
167   check(loc,
168         SV(
169 #if defined(_WIN32)
170             "%b='1'\t"
171 #elif defined(_AIX)      // defined(_WIN32)
172             "%b='1月'\t"
173 #elif defined(__APPLE__) // defined(_WIN32)
174             "%b=' 1'\t"
175 #else                    // defined(_WIN32)
176             "%b=' 1月'\t"
177 #endif                   // defined(_WIN32)
178             "%B='1月'\t"
179             "%C='19'\t"
180 #if defined(_WIN32)
181             "%h='1'\t"
182 #elif defined(_AIX)      // defined(_WIN32)
183             "%h='1月'\t"
184 #elif defined(__APPLE__) // defined(_WIN32)
185             "%h=' 1'\t"
186 #else                    // defined(_WIN32)
187             "%h=' 1月'\t"
188 #endif                   // defined(_WIN32)
189             "%y='70'\t"
190             "%Y='1970'\t"
191 #if defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__)
192             "%EC='19'\t"
193             "%Ey='70'\t"
194             "%EY='1970'\t"
195             "%Oy='70'\t"
196 #else  // defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__)
197             "%EC='昭和'\t"
198             "%Ey='45'\t"
199             "%EY='昭和45年'\t"
200             "%Oy='七十'\t"
201 #endif // defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__)
202             "\n"),
203         lfmt,
204         std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});
205 
206   check(loc,
207         SV(
208 
209 #if defined(_WIN32)
210             "%b='5'\t"
211 #elif defined(_AIX)      // defined(_WIN32)
212             "%b='5月'\t"
213 #elif defined(__APPLE__) // defined(_WIN32)
214             "%b=' 5'\t"
215 #else                    // defined(_WIN32)
216             "%b=' 5月'\t"
217 #endif                   // defined(_WIN32)
218             "%B='5月'\t"
219             "%C='20'\t"
220 #if defined(_WIN32)
221             "%h='5'\t"
222 #elif defined(_AIX)      // defined(_WIN32)
223             "%h='5月'\t"
224 #elif defined(__APPLE__) // defined(_WIN32)
225             "%h=' 5'\t"
226 #else                    // defined(_WIN32)
227             "%h=' 5月'\t"
228 #endif                   // defined(_WIN32)
229             "%y='04'\t"
230             "%Y='2004'\t"
231 #if defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__)
232             "%EC='20'\t"
233             "%Ey='04'\t"
234             "%EY='2004'\t"
235             "%Oy='04'\t"
236 #else  // defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__)
237             "%EC='平成'\t"
238             "%Ey='16'\t"
239             "%EY='平成16年'\t"
240             "%Oy='四'\t"
241 #endif // defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__)
242             "\n"),
243         lfmt,
244         std::chrono::year_month{std::chrono::year{2004}, std::chrono::May});
245 
246   std::locale::global(std::locale::classic());
247 }
248 
249 template <class CharT>
250 static void test() {
251   test_no_chrono_specs<CharT>();
252   test_invalid_values<CharT>();
253   test_valid_values<CharT>();
254 
255   check_invalid_types<CharT>(
256       {SV("b"), SV("B"), SV("C"), SV("EC"), SV("Ey"), SV("EY"), SV("h"), SV("m"), SV("Om"), SV("Oy"), SV("y"), SV("Y")},
257       std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});
258 
259   check_exception("The format specifier expects a '%' or a '}'",
260                   SV("{:A"),
261                   std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});
262   check_exception("The chrono specifiers contain a '{'",
263                   SV("{:%%{"),
264                   std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});
265   check_exception("End of input while parsing a conversion specifier",
266                   SV("{:%"),
267                   std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});
268   check_exception("End of input while parsing the modifier E",
269                   SV("{:%E"),
270                   std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});
271   check_exception("End of input while parsing the modifier O",
272                   SV("{:%O"),
273                   std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});
274 
275   // Precision not allowed
276   check_exception("The format specifier expects a '%' or a '}'",
277                   SV("{:.3}"),
278                   std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});
279 }
280 
281 int main(int, char**) {
282   test<char>();
283 
284 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
285   test<wchar_t>();
286 #endif
287 
288   return 0;
289 }
290