554 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++14, c++1710// UNSUPPORTED: no-localization11// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME12 13// XFAIL: availability-fp_to_chars-missing14 15// REQUIRES: locale.fr_FR.UTF-816// REQUIRES: locale.ja_JP.UTF-817 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 macros36#include "string_literal.h"37#include "test_macros.h"38 39template <class CharT>40static 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 output46 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 53template <class CharT>54static 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-locale96 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 Standard151 // 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#else182 "%p=''\t"183#endif184 "%R='00:00'\t"185 "%T='00:00:00'\t"186#ifdef _WIN32187 "%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#else193 "%r='12:00:00 '\t"194#endif195 "%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#else212 "%p=''\t"213#endif214 "%R='23:31'\t"215 "%T='23:31:30,123'\t"216#ifdef _WIN32217 "%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#else223 "%r='11:31:30 '\t"224#endif225 "%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#else242 "%p=''\t"243#endif244 "%R='03:02'\t"245 "%T='03:02:01,123456789012'\t"246#ifdef _WIN32247 "%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#else253 "%r='03:02:01 '\t"254#endif255 "%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#else272 "%p=''\t"273#endif274 "%R='01:01'\t"275 "%T='01:01:01'\t"276#ifdef _WIN32277 "%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#else283 "%r='01:01:01 '\t"284#endif285 "%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 "%p='午前'\t"303 "%R='00:00'\t"304 "%T='00:00:00'\t"305# if defined(__APPLE__) || defined(__FreeBSD__)306 "%r='12:00:00 午前'\t"307 "%X='00時00分00秒'\t"308 "%EX='00時00分00秒'\t"309# elif defined(_WIN32)310 "%r='0:00:00'\t"311 "%X='0:00:00'\t"312 "%EX='0:00:00'\t"313# else314 "%r='午前12:00:00'\t"315 "%X='00:00:00'\t"316 "%EX='00:00:00'\t"317# endif318 "\n"),319 lfmt,320 std::chrono::hh_mm_ss(0s));321 322 check(loc,323 SV("%H='23'\t"324 "%OH='23'\t"325 "%I='11'\t"326 "%OI='11'\t"327 "%M='31'\t"328 "%OM='31'\t"329 "%S='30.123'\t"330 "%OS='30.123'\t"331 "%p='午後'\t"332 "%R='23:31'\t"333 "%T='23:31:30.123'\t"334# if defined(__APPLE__) || defined(__FreeBSD__)335 "%r='11:31:30 午後'\t"336 "%X='23時31分30秒'\t"337 "%EX='23時31分30秒'\t"338# elif defined(_WIN32)339 "%r='23:31:30'\t"340 "%X='23:31:30'\t"341 "%EX='23:31:30'\t"342# else343 "%r='午後11:31:30'\t"344 "%X='23:31:30'\t"345 "%EX='23:31:30'\t"346# endif347 "\n"),348 lfmt,349 std::chrono::hh_mm_ss(23h + 31min + 30s + 123ms));350 351 check(loc,352 SV("-%H='03'\t"353 "%OH='03'\t"354 "%I='03'\t"355 "%OI='03'\t"356 "%M='02'\t"357 "%OM='02'\t"358 "%S='01.123456789012'\t"359 "%OS='01.123456789012'\t"360 "%p='午前'\t"361 "%R='03:02'\t"362 "%T='03:02:01.123456789012'\t"363# if defined(__APPLE__) || defined(__FreeBSD__)364 "%r='03:02:01 午前'\t"365 "%X='03時02分01秒'\t"366 "%EX='03時02分01秒'\t"367# elif defined(_WIN32)368 "%r='3:02:01'\t"369 "%X='3:02:01'\t"370 "%EX='3:02:01'\t"371# else372 "%r='午前03:02:01'\t"373 "%X='03:02:01'\t"374 "%EX='03:02:01'\t"375# endif376 "\n"),377 lfmt,378 std::chrono::hh_mm_ss(-(3h + 2min + 1s + std::chrono::duration<std::int64_t, std::pico>(123456789012))));379 380 check(loc,381 SV("%H='01'\t"382 "%OH='01'\t"383 "%I='01'\t"384 "%OI='01'\t"385 "%M='01'\t"386 "%OM='01'\t"387 "%S='01'\t"388 "%OS='01'\t"389 "%p='午前'\t"390 "%R='01:01'\t"391 "%T='01:01:01'\t"392# if defined(__APPLE__) || defined(__FreeBSD__)393 "%r='01:01:01 午前'\t"394 "%X='01時01分01秒'\t"395 "%EX='01時01分01秒'\t"396# elif defined(_WIN32)397 "%r='1:01:01'\t"398 "%X='1:01:01'\t"399 "%EX='1:01:01'\t"400# else401 "%r='午前01:01:01'\t"402 "%X='01:01:01'\t"403 "%EX='01:01:01'\t"404# endif405 "\n"),406 lfmt,407 std::chrono::hh_mm_ss(std::chrono::duration<double>(3661.123456)));408#else // defined(__APPLE__) || defined(_AIX) || defined(_WIN32)409 check(loc,410 SV("%H='00'\t"411 "%OH='〇'\t"412 "%I='12'\t"413 "%OI='十二'\t"414 "%M='00'\t"415 "%OM='〇'\t"416 "%S='00'\t"417 "%OS='〇'\t"418 "%p='午前'\t"419 "%R='00:00'\t"420 "%T='00:00:00'\t"421 "%r='午前12時00分00秒'\t"422 "%X='00時00分00秒'\t"423 "%EX='00時00分00秒'\t"424 "\n"),425 lfmt,426 std::chrono::hh_mm_ss(0s));427 428 // TODO FMT What should fractions be in alternate display mode?429 check(loc,430 SV("%H='23'\t"431 "%OH='二十三'\t"432 "%I='11'\t"433 "%OI='十一'\t"434 "%M='31'\t"435 "%OM='三十一'\t"436 "%S='30.123'\t"437 "%OS='三十.123'\t"438 "%p='午後'\t"439 "%R='23:31'\t"440 "%T='23:31:30.123'\t"441 "%r='午後11時31分30秒'\t"442 "%X='23時31分30秒'\t"443 "%EX='23時31分30秒'\t"444 "\n"),445 lfmt,446 std::chrono::hh_mm_ss(23h + 31min + 30s + 123ms));447 448 check(loc,449 SV("-%H='03'\t"450 "%OH='三'\t"451 "%I='03'\t"452 "%OI='三'\t"453 "%M='02'\t"454 "%OM='二'\t"455 "%S='01.123456789012'\t"456 "%OS='一.123456789012'\t"457 "%p='午前'\t"458 "%R='03:02'\t"459 "%T='03:02:01.123456789012'\t"460 "%r='午前03時02分01秒'\t"461 "%X='03時02分01秒'\t"462 "%EX='03時02分01秒'\t"463 "\n"),464 lfmt,465 std::chrono::hh_mm_ss(-(3h + 2min + 1s + std::chrono::duration<std::int64_t, std::pico>(123456789012))));466 467 check(loc,468 SV("%H='01'\t"469 "%OH='一'\t"470 "%I='01'\t"471 "%OI='一'\t"472 "%M='01'\t"473 "%OM='一'\t"474 "%S='01'\t"475 "%OS='一'\t"476 "%p='午前'\t"477 "%R='01:01'\t"478 "%T='01:01:01'\t"479 "%r='午前01時01分01秒'\t"480 "%X='01時01分01秒'\t"481 "%EX='01時01分01秒'\t"482 "\n"),483 lfmt,484 std::chrono::hh_mm_ss(std::chrono::duration<double>(3661.123456)));485#endif // defined(__APPLE__) || defined(_AIX) || defined(_WIN32)486 487 std::locale::global(std::locale::classic());488}489 490template <class CharT>491static void test_invalid_values() {492 using namespace std::literals::chrono_literals;493 494 // This looks odd, however the 24 hours is not valid for a 24 hour clock.495 // TODO FMT discuss what the "proper" behaviour is.496 check_exception("Formatting a hour needs a valid value", SV("{:%H"), std::chrono::hh_mm_ss{24h});497 check_exception("Formatting a hour needs a valid value", SV("{:%OH"), std::chrono::hh_mm_ss{24h});498 check_exception("Formatting a hour needs a valid value", SV("{:%I"), std::chrono::hh_mm_ss{24h});499 check_exception("Formatting a hour needs a valid value", SV("{:%OI"), std::chrono::hh_mm_ss{24h});500 check(SV("00"), SV("{:%M}"), std::chrono::hh_mm_ss{24h});501 check(SV("00"), SV("{:%OM}"), std::chrono::hh_mm_ss{24h});502 check(SV("00"), SV("{:%S}"), std::chrono::hh_mm_ss{24h});503 check(SV("00"), SV("{:%OS}"), std::chrono::hh_mm_ss{24h});504 check_exception("Formatting a hour needs a valid value", SV("{:%p"), std::chrono::hh_mm_ss{24h});505 check_exception("Formatting a hour needs a valid value", SV("{:%R"), std::chrono::hh_mm_ss{24h});506 check_exception("Formatting a hour needs a valid value", SV("{:%T"), std::chrono::hh_mm_ss{24h});507 check_exception("Formatting a hour needs a valid value", SV("{:%r"), std::chrono::hh_mm_ss{24h});508 check_exception("Formatting a hour needs a valid value", SV("{:%X"), std::chrono::hh_mm_ss{24h});509 check_exception("Formatting a hour needs a valid value", SV("{:%EX"), std::chrono::hh_mm_ss{24h});510}511 512template <class CharT>513static void test() {514 using namespace std::literals::chrono_literals;515 516 test_no_chrono_specs<CharT>();517 test_valid_values<CharT>();518 test_invalid_values<CharT>();519 check_invalid_types<CharT>(520 {SV("H"),521 SV("I"),522 SV("M"),523 SV("S"),524 SV("p"),525 SV("r"),526 SV("R"),527 SV("T"),528 SV("X"),529 SV("OH"),530 SV("OI"),531 SV("OM"),532 SV("OS"),533 SV("EX")},534 std::chrono::hh_mm_ss{0ms});535 536 check_exception("The format specifier expects a '%' or a '}'", SV("{:A"), std::chrono::hh_mm_ss{0ms});537 check_exception("The chrono specifiers contain a '{'", SV("{:%%{"), std::chrono::hh_mm_ss{0ms});538 check_exception("End of input while parsing a conversion specifier", SV("{:%"), std::chrono::hh_mm_ss{0ms});539 check_exception("End of input while parsing the modifier E", SV("{:%E"), std::chrono::hh_mm_ss{0ms});540 check_exception("End of input while parsing the modifier O", SV("{:%O"), std::chrono::hh_mm_ss{0ms});541 542 check_exception("The format specifier expects a '%' or a '}'", SV("{:.3}"), std::chrono::hh_mm_ss{0ms});543}544 545int main(int, char**) {546 test<char>();547 548#ifndef TEST_HAS_NO_WIDE_CHARACTERS549 test<wchar_t>();550#endif551 552 return 0;553}554