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

source code of libcxx/test/std/time/time.syn/formatter.hh_mm_ss.pass.cpp