xref: /llvm-project/libcxx/test/std/time/time.syn/formatter.hh_mm_ss.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 // XFAIL: availability-fp_to_chars-missing
14 
15 // REQUIRES: locale.fr_FR.UTF-8
16 // REQUIRES: locale.ja_JP.UTF-8
17 
18 // <chrono>
19 
20 // template<class Rep, class Period, class charT>
21 //   struct formatter<chrono::hh_mm_ss<duration<Rep, Period>>, charT>;
22 
23 #include <chrono>
24 #include <format>
25 
26 #include <cassert>
27 #include <concepts>
28 #include <locale>
29 #include <iostream>
30 #include <ratio>
31 #include <type_traits>
32 
33 #include "formatter_tests.h"
34 #include "make_string.h"
35 #include "platform_support.h" // locale name macros
36 #include "string_literal.h"
37 #include "test_macros.h"
38 
39 template <class CharT>
40 static void test_no_chrono_specs() {
41   using namespace std::literals::chrono_literals;
42 
43   std::locale::global(std::locale(LOCALE_fr_FR_UTF_8));
44 
45   // Non localized output
46   check(SV("00:00:00.000"), SV("{}"), std::chrono::hh_mm_ss{0ms});
47   check(SV("*00:00:00.000*"), SV("{:*^14}"), std::chrono::hh_mm_ss{0ms});
48   check(SV("*00:00:00.000"), SV("{:*>13}"), std::chrono::hh_mm_ss{0ms});
49 
50   std::locale::global(std::locale::classic());
51 }
52 
53 template <class CharT>
54 static void test_valid_values() {
55   using namespace std::literals::chrono_literals;
56 
57   constexpr std::basic_string_view<CharT> fmt = SV(
58       "{:"
59       "%%H='%H'%t"
60       "%%OH='%OH'%t"
61       "%%I='%I'%t"
62       "%%OI='%OI'%t"
63       "%%M='%M'%t"
64       "%%OM='%OM'%t"
65       "%%S='%S'%t"
66       "%%OS='%OS'%t"
67       "%%p='%p'%t"
68       "%%R='%R'%t"
69       "%%T='%T'%t"
70       "%%r='%r'%t"
71       "%%X='%X'%t"
72       "%%EX='%EX'%t"
73       "%n}");
74   constexpr std::basic_string_view<CharT> lfmt = SV(
75       "{:L"
76       "%%H='%H'%t"
77       "%%OH='%OH'%t"
78       "%%I='%I'%t"
79       "%%OI='%OI'%t"
80       "%%M='%M'%t"
81       "%%OM='%OM'%t"
82       "%%S='%S'%t"
83       "%%OS='%OS'%t"
84       "%%p='%p'%t"
85       "%%R='%R'%t"
86       "%%T='%T'%t"
87       "%%r='%r'%t"
88       "%%X='%X'%t"
89       "%%EX='%EX'%t"
90       "%n}");
91 
92   const std::locale loc(LOCALE_ja_JP_UTF_8);
93   std::locale::global(std::locale(LOCALE_fr_FR_UTF_8));
94 
95   // Non localized output using C-locale
96   check(SV("%H='00'\t"
97            "%OH='00'\t"
98            "%I='12'\t"
99            "%OI='12'\t"
100            "%M='00'\t"
101            "%OM='00'\t"
102            "%S='00'\t"
103            "%OS='00'\t"
104            "%p='AM'\t"
105            "%R='00:00'\t"
106            "%T='00:00:00'\t"
107            "%r='12:00:00 AM'\t"
108            "%X='00:00:00'\t"
109            "%EX='00:00:00'\t"
110            "\n"),
111         fmt,
112         std::chrono::hh_mm_ss(0s));
113 
114   check(SV("%H='23'\t"
115            "%OH='23'\t"
116            "%I='11'\t"
117            "%OI='11'\t"
118            "%M='31'\t"
119            "%OM='31'\t"
120            "%S='30.123'\t"
121            "%OS='30.123'\t"
122            "%p='PM'\t"
123            "%R='23:31'\t"
124            "%T='23:31:30.123'\t"
125            "%r='11:31:30 PM'\t"
126            "%X='23:31:30'\t"
127            "%EX='23:31:30'\t"
128            "\n"),
129         fmt,
130         std::chrono::hh_mm_ss(23h + 31min + 30s + 123ms));
131 
132   check(SV("-%H='03'\t"
133            "%OH='03'\t"
134            "%I='03'\t"
135            "%OI='03'\t"
136            "%M='02'\t"
137            "%OM='02'\t"
138            "%S='01.123456789012'\t"
139            "%OS='01.123456789012'\t"
140            "%p='AM'\t"
141            "%R='03:02'\t"
142            "%T='03:02:01.123456789012'\t"
143            "%r='03:02:01 AM'\t"
144            "%X='03:02:01'\t"
145            "%EX='03:02:01'\t"
146            "\n"),
147         fmt,
148         std::chrono::hh_mm_ss(-(3h + 2min + 1s + std::chrono::duration<std::int64_t, std::pico>(123456789012))));
149 
150   // The number of fractional seconds is 0 according to the Standard
151   // TODO FMT Determine what to do.
152   check(SV("%H='01'\t"
153            "%OH='01'\t"
154            "%I='01'\t"
155            "%OI='01'\t"
156            "%M='01'\t"
157            "%OM='01'\t"
158            "%S='01'\t"
159            "%OS='01'\t"
160            "%p='AM'\t"
161            "%R='01:01'\t"
162            "%T='01:01:01'\t"
163            "%r='01:01:01 AM'\t"
164            "%X='01:01:01'\t"
165            "%EX='01:01:01'\t"
166            "\n"),
167         fmt,
168         std::chrono::hh_mm_ss(std::chrono::duration<double>(3661.123456)));
169 
170   // Use the global locale (fr_FR)
171   check(SV("%H='00'\t"
172            "%OH='00'\t"
173            "%I='12'\t"
174            "%OI='12'\t"
175            "%M='00'\t"
176            "%OM='00'\t"
177            "%S='00'\t"
178            "%OS='00'\t"
179 #if defined(_AIX)
180            "%p='AM'\t"
181 #else
182            "%p=''\t"
183 #endif
184            "%R='00:00'\t"
185            "%T='00:00:00'\t"
186 #ifdef _WIN32
187            "%r='00:00:00'\t"
188 #elif defined(_AIX)
189            "%r='12:00:00 AM'\t"
190 #elif defined(__APPLE__) || defined(__FreeBSD__)
191            "%r=''\t"
192 #else
193            "%r='12:00:00 '\t"
194 #endif
195            "%X='00:00:00'\t"
196            "%EX='00:00:00'\t"
197            "\n"),
198         lfmt,
199         std::chrono::hh_mm_ss(0s));
200 
201   check(SV("%H='23'\t"
202            "%OH='23'\t"
203            "%I='11'\t"
204            "%OI='11'\t"
205            "%M='31'\t"
206            "%OM='31'\t"
207            "%S='30,123'\t"
208            "%OS='30,123'\t"
209 #if defined(_AIX)
210            "%p='PM'\t"
211 #else
212            "%p=''\t"
213 #endif
214            "%R='23:31'\t"
215            "%T='23:31:30,123'\t"
216 #ifdef _WIN32
217            "%r='23:31:30'\t"
218 #elif defined(_AIX)
219            "%r='11:31:30 PM'\t"
220 #elif defined(__APPLE__) || defined(__FreeBSD__)
221            "%r=''\t"
222 #else
223            "%r='11:31:30 '\t"
224 #endif
225            "%X='23:31:30'\t"
226            "%EX='23:31:30'\t"
227            "\n"),
228         lfmt,
229         std::chrono::hh_mm_ss(23h + 31min + 30s + 123ms));
230 
231   check(SV("-%H='03'\t"
232            "%OH='03'\t"
233            "%I='03'\t"
234            "%OI='03'\t"
235            "%M='02'\t"
236            "%OM='02'\t"
237            "%S='01,123456789012'\t"
238            "%OS='01,123456789012'\t"
239 #if defined(_AIX)
240            "%p='AM'\t"
241 #else
242            "%p=''\t"
243 #endif
244            "%R='03:02'\t"
245            "%T='03:02:01,123456789012'\t"
246 #ifdef _WIN32
247            "%r='03:02:01'\t"
248 #elif defined(_AIX)
249            "%r='03:02:01 AM'\t"
250 #elif defined(__APPLE__) || defined(__FreeBSD__)
251            "%r=''\t"
252 #else
253            "%r='03:02:01 '\t"
254 #endif
255            "%X='03:02:01'\t"
256            "%EX='03:02:01'\t"
257            "\n"),
258         lfmt,
259         std::chrono::hh_mm_ss(-(3h + 2min + 1s + std::chrono::duration<std::int64_t, std::pico>(123456789012))));
260 
261   check(SV("%H='01'\t"
262            "%OH='01'\t"
263            "%I='01'\t"
264            "%OI='01'\t"
265            "%M='01'\t"
266            "%OM='01'\t"
267            "%S='01'\t"
268            "%OS='01'\t"
269 #if defined(_AIX)
270            "%p='AM'\t"
271 #else
272            "%p=''\t"
273 #endif
274            "%R='01:01'\t"
275            "%T='01:01:01'\t"
276 #ifdef _WIN32
277            "%r='01:01:01'\t"
278 #elif defined(_AIX)
279            "%r='01:01:01 AM'\t"
280 #elif defined(__APPLE__) || defined(__FreeBSD__)
281            "%r=''\t"
282 #else
283            "%r='01:01:01 '\t"
284 #endif
285            "%X='01:01:01'\t"
286            "%EX='01:01:01'\t"
287            "\n"),
288         lfmt,
289         std::chrono::hh_mm_ss(std::chrono::duration<double>(3661.123456)));
290 
291   // Use supplied locale (ja_JP). This locale has a different alternate.
292 #if defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__)
293   check(loc,
294         SV("%H='00'\t"
295            "%OH='00'\t"
296            "%I='12'\t"
297            "%OI='12'\t"
298            "%M='00'\t"
299            "%OM='00'\t"
300            "%S='00'\t"
301            "%OS='00'\t"
302 #  if defined(__APPLE__)
303            "%p='AM'\t"
304 #  else
305            "%p='午前'\t"
306 #  endif
307            "%R='00:00'\t"
308            "%T='00:00:00'\t"
309 #  if defined(__APPLE__) || defined(__FreeBSD__)
310 #    if defined(__APPLE__)
311            "%r='12:00:00 AM'\t"
312 #    else
313            "%r='12:00:00 午前'\t"
314 #    endif
315            "%X='00時00分00秒'\t"
316            "%EX='00時00分00秒'\t"
317 #  elif defined(_WIN32)
318            "%r='0:00:00'\t"
319            "%X='0:00:00'\t"
320            "%EX='0:00:00'\t"
321 #  else
322            "%r='午前12:00:00'\t"
323            "%X='00:00:00'\t"
324            "%EX='00:00:00'\t"
325 #  endif
326            "\n"),
327         lfmt,
328         std::chrono::hh_mm_ss(0s));
329 
330   check(loc,
331         SV("%H='23'\t"
332            "%OH='23'\t"
333            "%I='11'\t"
334            "%OI='11'\t"
335            "%M='31'\t"
336            "%OM='31'\t"
337            "%S='30.123'\t"
338            "%OS='30.123'\t"
339 #  if defined(__APPLE__)
340            "%p='PM'\t"
341 #  else
342            "%p='午後'\t"
343 #  endif
344            "%R='23:31'\t"
345            "%T='23:31:30.123'\t"
346 #  if defined(__APPLE__) || defined(__FreeBSD__)
347 #    if defined(__APPLE__)
348            "%r='11:31:30 PM'\t"
349 #    else
350            "%r='11:31:30 午後'\t"
351 #    endif
352            "%X='23時31分30秒'\t"
353            "%EX='23時31分30秒'\t"
354 #  elif defined(_WIN32)
355            "%r='23:31:30'\t"
356            "%X='23:31:30'\t"
357            "%EX='23:31:30'\t"
358 #  else
359            "%r='午後11:31:30'\t"
360            "%X='23:31:30'\t"
361            "%EX='23:31:30'\t"
362 #  endif
363            "\n"),
364         lfmt,
365         std::chrono::hh_mm_ss(23h + 31min + 30s + 123ms));
366 
367   check(loc,
368         SV("-%H='03'\t"
369            "%OH='03'\t"
370            "%I='03'\t"
371            "%OI='03'\t"
372            "%M='02'\t"
373            "%OM='02'\t"
374            "%S='01.123456789012'\t"
375            "%OS='01.123456789012'\t"
376 #  if defined(__APPLE__)
377            "%p='AM'\t"
378 #  else
379            "%p='午前'\t"
380 #  endif
381            "%R='03:02'\t"
382            "%T='03:02:01.123456789012'\t"
383 #  if defined(__APPLE__) || defined(__FreeBSD__)
384 #    if defined(__APPLE__)
385            "%r='03:02:01 AM'\t"
386 #    else
387            "%r='03:02:01 午前'\t"
388 #    endif
389            "%X='03時02分01秒'\t"
390            "%EX='03時02分01秒'\t"
391 #  elif defined(_WIN32)
392            "%r='3:02:01'\t"
393            "%X='3:02:01'\t"
394            "%EX='3:02:01'\t"
395 #  else
396            "%r='午前03:02:01'\t"
397            "%X='03:02:01'\t"
398            "%EX='03:02:01'\t"
399 #  endif
400            "\n"),
401         lfmt,
402         std::chrono::hh_mm_ss(-(3h + 2min + 1s + std::chrono::duration<std::int64_t, std::pico>(123456789012))));
403 
404   check(loc,
405         SV("%H='01'\t"
406            "%OH='01'\t"
407            "%I='01'\t"
408            "%OI='01'\t"
409            "%M='01'\t"
410            "%OM='01'\t"
411            "%S='01'\t"
412            "%OS='01'\t"
413 #  if defined(__APPLE__)
414            "%p='AM'\t"
415 #  else
416            "%p='午前'\t"
417 #  endif
418            "%R='01:01'\t"
419            "%T='01:01:01'\t"
420 #  if defined(__APPLE__) || defined(__FreeBSD__)
421 #    if defined(__APPLE__)
422            "%r='01:01:01 AM'\t"
423 #    else
424            "%r='01:01:01 午前'\t"
425 #    endif
426            "%X='01時01分01秒'\t"
427            "%EX='01時01分01秒'\t"
428 #  elif defined(_WIN32)
429            "%r='1:01:01'\t"
430            "%X='1:01:01'\t"
431            "%EX='1:01:01'\t"
432 #  else
433            "%r='午前01:01:01'\t"
434            "%X='01:01:01'\t"
435            "%EX='01:01:01'\t"
436 #  endif
437            "\n"),
438         lfmt,
439         std::chrono::hh_mm_ss(std::chrono::duration<double>(3661.123456)));
440 #else  // defined(__APPLE__) || defined(_AIX) || defined(_WIN32)
441   check(loc,
442         SV("%H='00'\t"
443            "%OH='〇'\t"
444            "%I='12'\t"
445            "%OI='十二'\t"
446            "%M='00'\t"
447            "%OM='〇'\t"
448            "%S='00'\t"
449            "%OS='〇'\t"
450            "%p='午前'\t"
451            "%R='00:00'\t"
452            "%T='00:00:00'\t"
453            "%r='午前12時00分00秒'\t"
454            "%X='00時00分00秒'\t"
455            "%EX='00時00分00秒'\t"
456            "\n"),
457         lfmt,
458         std::chrono::hh_mm_ss(0s));
459 
460   // TODO FMT What should fractions be in alternate display mode?
461   check(loc,
462         SV("%H='23'\t"
463            "%OH='二十三'\t"
464            "%I='11'\t"
465            "%OI='十一'\t"
466            "%M='31'\t"
467            "%OM='三十一'\t"
468            "%S='30.123'\t"
469            "%OS='三十.123'\t"
470            "%p='午後'\t"
471            "%R='23:31'\t"
472            "%T='23:31:30.123'\t"
473            "%r='午後11時31分30秒'\t"
474            "%X='23時31分30秒'\t"
475            "%EX='23時31分30秒'\t"
476            "\n"),
477         lfmt,
478         std::chrono::hh_mm_ss(23h + 31min + 30s + 123ms));
479 
480   check(loc,
481         SV("-%H='03'\t"
482            "%OH='三'\t"
483            "%I='03'\t"
484            "%OI='三'\t"
485            "%M='02'\t"
486            "%OM='二'\t"
487            "%S='01.123456789012'\t"
488            "%OS='一.123456789012'\t"
489            "%p='午前'\t"
490            "%R='03:02'\t"
491            "%T='03:02:01.123456789012'\t"
492            "%r='午前03時02分01秒'\t"
493            "%X='03時02分01秒'\t"
494            "%EX='03時02分01秒'\t"
495            "\n"),
496         lfmt,
497         std::chrono::hh_mm_ss(-(3h + 2min + 1s + std::chrono::duration<std::int64_t, std::pico>(123456789012))));
498 
499   check(loc,
500         SV("%H='01'\t"
501            "%OH='一'\t"
502            "%I='01'\t"
503            "%OI='一'\t"
504            "%M='01'\t"
505            "%OM='一'\t"
506            "%S='01'\t"
507            "%OS='一'\t"
508            "%p='午前'\t"
509            "%R='01:01'\t"
510            "%T='01:01:01'\t"
511            "%r='午前01時01分01秒'\t"
512            "%X='01時01分01秒'\t"
513            "%EX='01時01分01秒'\t"
514            "\n"),
515         lfmt,
516         std::chrono::hh_mm_ss(std::chrono::duration<double>(3661.123456)));
517 #endif // defined(__APPLE__) || defined(_AIX) || defined(_WIN32)
518 
519   std::locale::global(std::locale::classic());
520 }
521 
522 template <class CharT>
523 static void test_invalid_values() {
524   using namespace std::literals::chrono_literals;
525 
526   // This looks odd, however the 24 hours is not valid for a 24 hour clock.
527   // TODO FMT discuss what the "proper" behaviour is.
528   check_exception("Formatting a hour needs a valid value", SV("{:%H"), std::chrono::hh_mm_ss{24h});
529   check_exception("Formatting a hour needs a valid value", SV("{:%OH"), std::chrono::hh_mm_ss{24h});
530   check_exception("Formatting a hour needs a valid value", SV("{:%I"), std::chrono::hh_mm_ss{24h});
531   check_exception("Formatting a hour needs a valid value", SV("{:%OI"), std::chrono::hh_mm_ss{24h});
532   check(SV("00"), SV("{:%M}"), std::chrono::hh_mm_ss{24h});
533   check(SV("00"), SV("{:%OM}"), std::chrono::hh_mm_ss{24h});
534   check(SV("00"), SV("{:%S}"), std::chrono::hh_mm_ss{24h});
535   check(SV("00"), SV("{:%OS}"), std::chrono::hh_mm_ss{24h});
536   check_exception("Formatting a hour needs a valid value", SV("{:%p"), std::chrono::hh_mm_ss{24h});
537   check_exception("Formatting a hour needs a valid value", SV("{:%R"), std::chrono::hh_mm_ss{24h});
538   check_exception("Formatting a hour needs a valid value", SV("{:%T"), std::chrono::hh_mm_ss{24h});
539   check_exception("Formatting a hour needs a valid value", SV("{:%r"), std::chrono::hh_mm_ss{24h});
540   check_exception("Formatting a hour needs a valid value", SV("{:%X"), std::chrono::hh_mm_ss{24h});
541   check_exception("Formatting a hour needs a valid value", SV("{:%EX"), std::chrono::hh_mm_ss{24h});
542 }
543 
544 template <class CharT>
545 static void test() {
546   using namespace std::literals::chrono_literals;
547 
548   test_no_chrono_specs<CharT>();
549   test_valid_values<CharT>();
550   test_invalid_values<CharT>();
551   check_invalid_types<CharT>(
552       {SV("H"),
553        SV("I"),
554        SV("M"),
555        SV("S"),
556        SV("p"),
557        SV("r"),
558        SV("R"),
559        SV("T"),
560        SV("X"),
561        SV("OH"),
562        SV("OI"),
563        SV("OM"),
564        SV("OS"),
565        SV("EX")},
566       std::chrono::hh_mm_ss{0ms});
567 
568   check_exception("The format specifier expects a '%' or a '}'", SV("{:A"), std::chrono::hh_mm_ss{0ms});
569   check_exception("The chrono specifiers contain a '{'", SV("{:%%{"), std::chrono::hh_mm_ss{0ms});
570   check_exception("End of input while parsing a conversion specifier", SV("{:%"), std::chrono::hh_mm_ss{0ms});
571   check_exception("End of input while parsing the modifier E", SV("{:%E"), std::chrono::hh_mm_ss{0ms});
572   check_exception("End of input while parsing the modifier O", SV("{:%O"), std::chrono::hh_mm_ss{0ms});
573 
574   check_exception("The format specifier expects a '%' or a '}'", SV("{:.3}"), std::chrono::hh_mm_ss{0ms});
575 }
576 
577 int main(int, char**) {
578   test<char>();
579 
580 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
581   test<wchar_t>();
582 #endif
583 
584   return 0;
585 }
586