2350 lines · cpp
1//===-- Unittests for strftime --------------------------------------------===//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#include "hdr/types/struct_tm.h"10#include "src/__support/CPP/array.h"11#include "src/__support/integer_to_string.h"12#include "src/time/strftime.h"13#include "src/time/time_constants.h"14#include "test/UnitTest/Test.h"15 16// Copied from sprintf_test.cpp.17// TODO: put this somewhere more reusable, it's handy.18// Subtract 1 from sizeof(expected_str) to account for the null byte.19#define EXPECT_STREQ_LEN(actual_written, actual_str, expected_str) \20 EXPECT_EQ(actual_written, sizeof(expected_str) - 1); \21 EXPECT_STREQ(actual_str, expected_str);22 23constexpr int get_adjusted_year(int year) {24 // tm_year counts years since 1900, so subtract 1900 to get the tm_year for a25 // given raw year.26 return year - LIBC_NAMESPACE::time_constants::TIME_YEAR_BASE;27}28 29// TODO: Move this somewhere it can be reused. It seems like a useful tool to30// have.31// A helper class to generate simple padded numbers. It places the result in its32// internal buffer, which is cleared on every call.33class SimplePaddedNum {34 static constexpr int BUFF_LEN = 16;35 char buff[BUFF_LEN];36 size_t cur_len; // length of string currently in buff37 38 void clear_buff() {39 // TODO: builtin_memset?40 for (int i = 0; i < BUFF_LEN; ++i)41 buff[i] = '\0';42 }43 44public:45 SimplePaddedNum() = default;46 47 // PRECONDITIONS: 0 < num < 2**31, min_width < 1648 // Returns: Pointer to the start of the padded number as a string, stored in49 // the internal buffer.50 char *get_padded_num(int num, size_t min_width, char padding_char = '0') {51 clear_buff();52 53 // we're not handling the negative sign here, so padding on negative numbers54 // will be incorrect. For this use case I consider that to be a reasonable55 // tradeoff for simplicity. This is more meant for the cases where we can56 // loop through all the possibilities, and for time those are all positive.57 LIBC_NAMESPACE::IntegerToString<int> raw(num);58 auto str = raw.view();59 int leading_zeroes = static_cast<int>(min_width - raw.size());60 61 int i = 0;62 for (; static_cast<int>(i) < leading_zeroes; ++i)63 buff[i] = padding_char;64 for (size_t str_cur = 0, e = str.size(); str_cur < e; ++i, ++str_cur)65 buff[i] = str[str_cur];66 cur_len = i;67 return buff;68 }69 70 size_t get_str_len() { return cur_len; }71};72 73TEST(LlvmLibcStrftimeTest, ConstantConversions) {74 // this tests %n, %t, and %%, which read nothing.75 struct tm time;76 char buffer[100];77 size_t written = 0;78 79 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%n", &time);80 EXPECT_STREQ_LEN(written, buffer, "\n");81 82 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%t", &time);83 EXPECT_STREQ_LEN(written, buffer, "\t");84 85 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%%", &time);86 EXPECT_STREQ_LEN(written, buffer, "%");87}88 89TEST(LlvmLibcStrftimeTest, CenturyTests) {90 // this tests %C, which reads: [tm_year]91 struct tm time;92 char buffer[100];93 size_t written = 0;94 95 // basic tests96 time.tm_year = get_adjusted_year(2022);97 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%C", &time);98 EXPECT_STREQ_LEN(written, buffer, "20");99 100 time.tm_year = get_adjusted_year(11900);101 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%C", &time);102 EXPECT_STREQ_LEN(written, buffer, "119");103 104 time.tm_year = get_adjusted_year(1900);105 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%C", &time);106 EXPECT_STREQ_LEN(written, buffer, "19");107 108 time.tm_year = get_adjusted_year(900);109 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%C", &time);110 EXPECT_STREQ_LEN(written, buffer, "09");111 112 time.tm_year = get_adjusted_year(0);113 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%C", &time);114 EXPECT_STREQ_LEN(written, buffer, "00");115 116 // This case does not match what glibc does.117 // Both the C standard and Posix say %C is "Replaced by the year divided by118 // 100 and truncated to an integer, as a decimal number."119 // What glibc does is it returns the century for the provided year.120 // The difference is that glibc returns "-1" as the century for year -1, and121 // "-2" for year -101.122 // This case demonstrates that LLVM-libc instead just divides by 100, and123 // returns the result. "00" for year -1, and "-1" for year -101.124 // Personally, neither of these really feels right. Posix has a table of125 // examples where it treats "%C%y" as identical to "%Y". Neither of these126 // behaviors would handle that properly, you'd either get "-199" or "0099"127 // (since %y always returns a number in the range [00-99]).128 time.tm_year = get_adjusted_year(-1);129 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%C", &time);130 EXPECT_STREQ_LEN(written, buffer, "00");131 132 time.tm_year = get_adjusted_year(-101);133 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%C", &time);134 EXPECT_STREQ_LEN(written, buffer, "-1");135 136 time.tm_year = get_adjusted_year(-9001);137 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%C", &time);138 EXPECT_STREQ_LEN(written, buffer, "-90");139 140 time.tm_year = get_adjusted_year(-10001);141 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%C", &time);142 EXPECT_STREQ_LEN(written, buffer, "-100");143 144 // width tests (with the 0 flag, since the default padding is undefined).145 time.tm_year = get_adjusted_year(2023);146 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01C", &time);147 EXPECT_STREQ_LEN(written, buffer, "20");148 149 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02C", &time);150 EXPECT_STREQ_LEN(written, buffer, "20");151 152 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05C", &time);153 EXPECT_STREQ_LEN(written, buffer, "00020");154 155 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%010C", &time);156 EXPECT_STREQ_LEN(written, buffer, "0000000020");157 158 time.tm_year = get_adjusted_year(900);159 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01C", &time);160 EXPECT_STREQ_LEN(written, buffer, "9");161 162 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02C", &time);163 EXPECT_STREQ_LEN(written, buffer, "09");164 165 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05C", &time);166 EXPECT_STREQ_LEN(written, buffer, "00009");167 168 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%010C", &time);169 EXPECT_STREQ_LEN(written, buffer, "0000000009");170 171 time.tm_year = get_adjusted_year(12345);172 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01C", &time);173 EXPECT_STREQ_LEN(written, buffer, "123");174 175 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02C", &time);176 EXPECT_STREQ_LEN(written, buffer, "123");177 178 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05C", &time);179 EXPECT_STREQ_LEN(written, buffer, "00123");180 181 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%010C", &time);182 EXPECT_STREQ_LEN(written, buffer, "0000000123");183 184 time.tm_year = get_adjusted_year(-123);185 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01C", &time);186 EXPECT_STREQ_LEN(written, buffer, "-1");187 188 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02C", &time);189 EXPECT_STREQ_LEN(written, buffer, "-1");190 191 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05C", &time);192 EXPECT_STREQ_LEN(written, buffer, "-0001");193 194 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%010C", &time);195 EXPECT_STREQ_LEN(written, buffer, "-000000001");196 197 // '+' flag tests198 time.tm_year = get_adjusted_year(2023);199 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+1C", &time);200 EXPECT_STREQ_LEN(written, buffer, "20");201 202 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+2C", &time);203 EXPECT_STREQ_LEN(written, buffer, "20");204 205 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+5C", &time);206 EXPECT_STREQ_LEN(written, buffer, "+0020");207 208 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+10C", &time);209 EXPECT_STREQ_LEN(written, buffer, "+000000020");210 211 time.tm_year = get_adjusted_year(900);212 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+1C", &time);213 EXPECT_STREQ_LEN(written, buffer, "9");214 215 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+2C", &time);216 EXPECT_STREQ_LEN(written, buffer, "09");217 218 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+5C", &time);219 EXPECT_STREQ_LEN(written, buffer, "+0009");220 221 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+10C", &time);222 EXPECT_STREQ_LEN(written, buffer, "+000000009");223 224 time.tm_year = get_adjusted_year(12345);225 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+1C", &time);226 EXPECT_STREQ_LEN(written, buffer, "+123");227 228 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+2C", &time);229 EXPECT_STREQ_LEN(written, buffer, "+123");230 231 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+5C", &time);232 EXPECT_STREQ_LEN(written, buffer, "+0123");233 234 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+10C", &time);235 EXPECT_STREQ_LEN(written, buffer, "+000000123");236 237 time.tm_year = get_adjusted_year(-123);238 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+1C", &time);239 EXPECT_STREQ_LEN(written, buffer, "-1");240 241 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+2C", &time);242 EXPECT_STREQ_LEN(written, buffer, "-1");243 244 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+5C", &time);245 EXPECT_STREQ_LEN(written, buffer, "-0001");246 247 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+10C", &time);248 EXPECT_STREQ_LEN(written, buffer, "-000000001");249 250 // Posix specified tests:251 time.tm_year = get_adjusted_year(17);252 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%C", &time);253 EXPECT_STREQ_LEN(written, buffer, "00");254 255 time.tm_year = get_adjusted_year(270);256 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%C", &time);257 EXPECT_STREQ_LEN(written, buffer, "02");258 259 time.tm_year = get_adjusted_year(270);260 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+3C", &time);261 EXPECT_STREQ_LEN(written, buffer, "+02");262 263 time.tm_year = get_adjusted_year(12345);264 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+3C", &time);265 EXPECT_STREQ_LEN(written, buffer, "+123");266 267 time.tm_year = get_adjusted_year(12345);268 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%04C", &time);269 EXPECT_STREQ_LEN(written, buffer, "0123");270 271 time.tm_year = get_adjusted_year(12345);272 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+4C", &time);273 EXPECT_STREQ_LEN(written, buffer, "+123");274 275 time.tm_year = get_adjusted_year(123456);276 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%06C", &time);277 EXPECT_STREQ_LEN(written, buffer, "001234");278 279 time.tm_year = get_adjusted_year(123456);280 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+6C", &time);281 EXPECT_STREQ_LEN(written, buffer, "+01234");282}283 284TEST(LlvmLibcStrftimeTest, TwoDigitDayOfMonth) {285 using LIBC_NAMESPACE::time_constants::MAX_DAYS_PER_MONTH;286 // this tests %d, which reads: [tm_mday]287 struct tm time;288 char buffer[100];289 size_t written = 0;290 SimplePaddedNum spn;291 292 // Tests on all the well defined values293 for (int i = 1; i <= MAX_DAYS_PER_MONTH; ++i) {294 time.tm_mday = i;295 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%d", &time);296 char *result = spn.get_padded_num(i, 2);297 298 ASSERT_STREQ(buffer, result);299 ASSERT_EQ(written, size_t(2));300 }301 302 // padding is technically undefined for this conversion, but we support it, so303 // we need to test it.304 time.tm_mday = 5;305 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01d", &time);306 EXPECT_STREQ_LEN(written, buffer, "5");307 308 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02d", &time);309 EXPECT_STREQ_LEN(written, buffer, "05");310 311 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05d", &time);312 EXPECT_STREQ_LEN(written, buffer, "00005");313 314 time.tm_mday = 31;315 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01d", &time);316 EXPECT_STREQ_LEN(written, buffer, "31");317 318 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02d", &time);319 EXPECT_STREQ_LEN(written, buffer, "31");320 321 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05d", &time);322 EXPECT_STREQ_LEN(written, buffer, "00031");323}324 325TEST(LlvmLibcStrftimeTest, MinDigitDayOfMonth) {326 // this tests %e, which reads: [tm_mday]327 struct tm time;328 char buffer[100];329 size_t written = 0;330 SimplePaddedNum spn;331 332 // Tests on all the well defined values333 for (int i = 1; i < 32; ++i) {334 time.tm_mday = i;335 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%e", &time);336 char *result = spn.get_padded_num(i, 2, ' ');337 338 ASSERT_STREQ(buffer, result);339 ASSERT_EQ(written, spn.get_str_len());340 }341 342 // padding is technically undefined for this conversion, but we support it, so343 // we need to test it.344 time.tm_mday = 5;345 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01e", &time);346 EXPECT_STREQ_LEN(written, buffer, "5");347 348 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02e", &time);349 EXPECT_STREQ_LEN(written, buffer, "05");350 351 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05e", &time);352 EXPECT_STREQ_LEN(written, buffer, "00005");353 354 time.tm_mday = 31;355 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01e", &time);356 EXPECT_STREQ_LEN(written, buffer, "31");357 358 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02e", &time);359 EXPECT_STREQ_LEN(written, buffer, "31");360 361 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05e", &time);362 EXPECT_STREQ_LEN(written, buffer, "00031");363}364 365TEST(LlvmLibcStrftimeTest, ISOYearOfCentury) {366 // this tests %g, which reads: [tm_year, tm_wday, tm_yday]367 368 // A brief primer on ISO dates:369 // 1) ISO weeks start on Monday and end on Sunday370 // 2) ISO years start on the Monday of the 1st ISO week of the year371 // 3) The 1st ISO week of the ISO year has the 4th day of the Gregorian year.372 373 struct tm time;374 char buffer[100];375 size_t written = 0;376 SimplePaddedNum spn;377 378 // a sunday in the middle of the year. No need to worry about rounding379 time.tm_wday = 0;380 time.tm_yday = 100;381 382 // Test the easy cases383 for (int i = 0; i < 102; ++i) {384 time.tm_year = i;385 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%g", &time);386 char *result = spn.get_padded_num(i % 100, 2);387 388 ASSERT_STREQ(buffer, result);389 ASSERT_EQ(written, spn.get_str_len());390 }391 392 // Test the harder to round cases393 394 // not a leap year. Not relevant for the start-of-year tests, but it does395 // matter for the end-of-year tests.396 time.tm_year = 99;397 398 /*399This table has an X for each day that should be in the previous year,400everywhere else should be in the current year.401 402 yday403 0123456404 i 1 Monday405 s 2 Tuesday406 o 3 Wednesday407 w 4 Thursday408 d 5 X Friday409 a 6 XX Saturday410 y 7 XXX Sunday411*/412 413 // check the first days of the year414 for (int yday = 0; yday < 5; ++yday) {415 for (int iso_wday = LIBC_NAMESPACE::time_constants::MONDAY; iso_wday < 8;416 ++iso_wday) {417 // start with monday, to match the ISO week.418 time.tm_wday = iso_wday % LIBC_NAMESPACE::time_constants::DAYS_PER_WEEK;419 time.tm_yday = yday;420 421 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%g", &time);422 423 if (iso_wday <= LIBC_NAMESPACE::time_constants::THURSDAY || yday >= 3) {424 // monday - thursday are never in the previous year, nor are the 4th and425 // after.426 EXPECT_STREQ_LEN(written, buffer, "99");427 } else {428 // iso_wday is 5, 6, or 7 and yday is 0, 1, or 2.429 // days_since_thursday is therefor 1, 2, or 3.430 const int days_since_thursday =431 iso_wday - LIBC_NAMESPACE::time_constants::THURSDAY;432 433 if (days_since_thursday > yday) {434 EXPECT_STREQ_LEN(written, buffer, "98");435 } else {436 EXPECT_STREQ_LEN(written, buffer, "99");437 }438 }439 }440 }441 442 /*443 Similar to above, but the Xs represent being in the NEXT year. Also the444 top counts down until the end of the year.445 446 year end - yday447 6543210448 i 1 XXX Monday449 s 2 XX Tuesday450 o 3 X Wednesday451 w 4 Thursday452 d 5 Friday453 a 6 Saturday454 y 7 Sunday455 456 457 If we place the charts next to each other, you can more easily see the458 pattern:459 460year end - yday yday461 6543210 0123456462 i 1 XXX Monday463 s 2 XX Tuesday464 o 3 X Wednesday465 w 4 Thursday466 d 5 X Friday467 a 6 XX Saturday468 y 7 XXX Sunday469 470 From this we can see that thursday is always in the same ISO and regular471 year, because the ISO year starts on the week with the 4th. Since Thursday472 is at least 3 days from either edge of the ISO week, the first thursday of473 the year is always in the first ISO week of the year.474 */475 476 // set up all the extra stuff to cover leap years.477 struct tm time_leap_year;478 char buffer_leap_year[100];479 size_t written_leap_year = 0;480 time_leap_year = time;481 time_leap_year.tm_year = 100; // 2000 is a leap year.482 483 // check the last days of the year. Checking 5 to make sure all the leap year484 // cases are covered as well.485 for (int days_left = 0; days_left < 5; ++days_left) {486 for (int iso_wday = LIBC_NAMESPACE::time_constants::MONDAY; iso_wday < 8;487 ++iso_wday) {488 // start with monday, to match the ISO week.489 time.tm_wday = iso_wday % LIBC_NAMESPACE::time_constants::DAYS_PER_WEEK;490 // subtract 1 from the max yday to handle yday being 0-indexed.491 time.tm_yday = LIBC_NAMESPACE::time_constants::DAYS_PER_NON_LEAP_YEAR -492 1 - days_left;493 494 time_leap_year.tm_wday =495 iso_wday % LIBC_NAMESPACE::time_constants::DAYS_PER_WEEK;496 time_leap_year.tm_yday =497 LIBC_NAMESPACE::time_constants::LAST_DAY_OF_LEAP_YEAR - days_left;498 499 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%g", &time);500 written_leap_year = LIBC_NAMESPACE::strftime(501 buffer_leap_year, sizeof(buffer_leap_year), "%g", &time_leap_year);502 503 if (iso_wday >= LIBC_NAMESPACE::time_constants::THURSDAY ||504 days_left >= 3) {505 // thursday - sunday are never in the next year, nor are days more than506 // 3 days before the end.507 EXPECT_STREQ_LEN(written, buffer, "99");508 EXPECT_STREQ_LEN(written_leap_year, buffer_leap_year, "00");509 } else {510 // iso_wday is 1, 2 or 3 and days_left is 0, 1, or 2511 if (iso_wday + days_left <= 3) {512 EXPECT_STREQ_LEN(written, buffer, "00");513 EXPECT_STREQ_LEN(written_leap_year, buffer_leap_year, "01");514 } else {515 EXPECT_STREQ_LEN(written, buffer, "99");516 EXPECT_STREQ_LEN(written_leap_year, buffer_leap_year, "00");517 }518 }519 }520 }521 522 // padding is technically undefined for this conversion, but we support it, so523 // we need to test it.524 time.tm_year = 5;525 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01g", &time);526 EXPECT_STREQ_LEN(written, buffer, "5");527 528 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02g", &time);529 EXPECT_STREQ_LEN(written, buffer, "05");530 531 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05g", &time);532 EXPECT_STREQ_LEN(written, buffer, "00005");533 534 time.tm_year = 31;535 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01g", &time);536 EXPECT_STREQ_LEN(written, buffer, "31");537 538 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02g", &time);539 EXPECT_STREQ_LEN(written, buffer, "31");540 541 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05g", &time);542 EXPECT_STREQ_LEN(written, buffer, "00031");543}544 545TEST(LlvmLibcStrftimeTest, ISOYear) {546 // this tests %G, which reads: [tm_year, tm_wday, tm_yday]547 548 // This stuff is all the same as above, but for brevity I'm not going to549 // duplicate all the comments explaining exactly how ISO years work. The550 // general comments are still here though.551 552 struct tm time;553 char buffer[100];554 size_t written = 0;555 SimplePaddedNum spn;556 557 // a sunday in the middle of the year. No need to worry about rounding558 time.tm_wday = 0;559 time.tm_yday = 100;560 561 // Test the easy cases562 for (int i = 1; i < 10000; ++i) {563 time.tm_year = get_adjusted_year(i);564 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%G", &time);565 char *result = spn.get_padded_num(i, 4);566 567 ASSERT_STREQ(buffer, result);568 ASSERT_EQ(written, spn.get_str_len());569 }570 571 // also check it handles years with extra digits properly572 time.tm_year = get_adjusted_year(12345);573 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%G", &time);574 EXPECT_STREQ_LEN(written, buffer, "12345");575 576 // Test the harder to round cases577 578 // not a leap year. Not relevant for the start-of-year tests, but it does579 // matter for the end-of-year tests.580 time.tm_year = get_adjusted_year(1999);581 582 // check the first days of the year583 for (int yday = 0; yday < 5; ++yday) {584 for (int iso_wday = 1; iso_wday < 8; ++iso_wday) {585 // start with monday, to match the ISO week.586 time.tm_wday = iso_wday % LIBC_NAMESPACE::time_constants::DAYS_PER_WEEK;587 time.tm_yday = yday;588 589 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%G", &time);590 591 if (iso_wday <= LIBC_NAMESPACE::time_constants::THURSDAY || yday >= 4) {592 // monday - thursday are never in the previous year, nor are the 4th and593 // after.594 EXPECT_STREQ_LEN(written, buffer, "1999");595 } else {596 // iso_wday is 5, 6, or 7 and yday is 0, 1, or 2.597 // days_since_thursday is therefor 1, 2, or 3.598 const int days_since_thursday =599 iso_wday - LIBC_NAMESPACE::time_constants::THURSDAY;600 601 if (days_since_thursday > yday) {602 EXPECT_STREQ_LEN(written, buffer, "1998");603 } else {604 EXPECT_STREQ_LEN(written, buffer, "1999");605 }606 }607 }608 }609 610 // set up all the extra stuff to cover leap years.611 struct tm time_leap_year;612 char buffer_leap_year[100];613 size_t written_leap_year = 0;614 time_leap_year = time;615 time_leap_year.tm_year = 100; // 2000 is a leap year.616 617 // check the last days of the year. Checking 5 to make sure all the leap year618 // cases are covered as well.619 for (int days_left = 0; days_left < 5; ++days_left) {620 for (int iso_wday = 1; iso_wday < 8; ++iso_wday) {621 // start with monday, to match the ISO week.622 time.tm_wday = iso_wday % LIBC_NAMESPACE::time_constants::DAYS_PER_WEEK;623 // subtract 1 from the max yday to handle yday being 0-indexed.624 time.tm_yday =625 LIBC_NAMESPACE::time_constants::LAST_DAY_OF_NON_LEAP_YEAR - days_left;626 627 time_leap_year.tm_wday =628 iso_wday % LIBC_NAMESPACE::time_constants::DAYS_PER_WEEK;629 time_leap_year.tm_yday =630 LIBC_NAMESPACE::time_constants::LAST_DAY_OF_LEAP_YEAR - days_left;631 632 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%G", &time);633 written_leap_year = LIBC_NAMESPACE::strftime(634 buffer_leap_year, sizeof(buffer_leap_year), "%G", &time_leap_year);635 636 if (iso_wday >= 4 || days_left >= 3) {637 // thursday - sunday are never in the next year, nor are days more than638 // 3 days before the end.639 EXPECT_STREQ_LEN(written, buffer, "1999");640 EXPECT_STREQ_LEN(written_leap_year, buffer_leap_year, "2000");641 } else {642 // iso_wday is 1, 2 or 3 and days_left is 0, 1, or 2643 if (iso_wday + days_left <= 3) {644 EXPECT_STREQ_LEN(written, buffer, "2000");645 EXPECT_STREQ_LEN(written_leap_year, buffer_leap_year, "2001");646 } else {647 EXPECT_STREQ_LEN(written, buffer, "1999");648 EXPECT_STREQ_LEN(written_leap_year, buffer_leap_year, "2000");649 }650 }651 }652 }653 654 // padding is technically undefined for this conversion, but we support it, so655 // we need to test it.656 time.tm_year = get_adjusted_year(5);657 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01G", &time);658 EXPECT_STREQ_LEN(written, buffer, "5");659 660 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02G", &time);661 EXPECT_STREQ_LEN(written, buffer, "05");662 663 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05G", &time);664 EXPECT_STREQ_LEN(written, buffer, "00005");665 666 time.tm_year = get_adjusted_year(31);667 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01G", &time);668 EXPECT_STREQ_LEN(written, buffer, "31");669 670 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02G", &time);671 EXPECT_STREQ_LEN(written, buffer, "31");672 673 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05G", &time);674 EXPECT_STREQ_LEN(written, buffer, "00031");675 676 time.tm_year = get_adjusted_year(2001);677 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01G", &time);678 EXPECT_STREQ_LEN(written, buffer, "2001");679 680 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02G", &time);681 EXPECT_STREQ_LEN(written, buffer, "2001");682 683 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05G", &time);684 EXPECT_STREQ_LEN(written, buffer, "02001");685}686 687TEST(LlvmLibcStrftimeTest, TwentyFourHour) {688 // this tests %H, which reads: [tm_hour]689 struct tm time;690 char buffer[100];691 size_t written = 0;692 SimplePaddedNum spn;693 694 // Tests on all the well defined values695 for (int i = 0; i < 24; ++i) {696 time.tm_hour = i;697 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%H", &time);698 char *result = spn.get_padded_num(i, 2);699 700 ASSERT_STREQ(buffer, result);701 ASSERT_EQ(written, spn.get_str_len());702 }703 704 // padding is technically undefined for this conversion, but we support it, so705 // we need to test it.706 time.tm_hour = 5;707 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01H", &time);708 EXPECT_STREQ_LEN(written, buffer, "5");709 710 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02H", &time);711 EXPECT_STREQ_LEN(written, buffer, "05");712 713 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05H", &time);714 EXPECT_STREQ_LEN(written, buffer, "00005");715 716 time.tm_hour = 23;717 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01H", &time);718 EXPECT_STREQ_LEN(written, buffer, "23");719 720 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02H", &time);721 EXPECT_STREQ_LEN(written, buffer, "23");722 723 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05H", &time);724 EXPECT_STREQ_LEN(written, buffer, "00023");725}726 727TEST(LlvmLibcStrftimeTest, TwelveHour) {728 // this tests %I, which reads: [tm_hour]729 struct tm time;730 char buffer[100];731 size_t written = 0;732 SimplePaddedNum spn;733 734 time.tm_hour = 0;735 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%I", &time);736 EXPECT_STREQ_LEN(written, buffer, "12");737 738 // Tests on all the well defined values, except 0 since it was easier to739 // special case it.740 for (int i = 1; i <= 12; ++i) {741 char *result = spn.get_padded_num(i, 2);742 743 time.tm_hour = i;744 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%I", &time);745 ASSERT_STREQ(buffer, result);746 ASSERT_EQ(written, spn.get_str_len());747 748 // hour + 12 should give the same result749 time.tm_hour = i + 12;750 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%I", &time);751 ASSERT_STREQ(buffer, result);752 ASSERT_EQ(written, spn.get_str_len());753 }754 755 // padding is technically undefined for this conversion, but we support it, so756 // we need to test it.757 time.tm_hour = 5;758 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01I", &time);759 EXPECT_STREQ_LEN(written, buffer, "5");760 761 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02I", &time);762 EXPECT_STREQ_LEN(written, buffer, "05");763 764 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05I", &time);765 EXPECT_STREQ_LEN(written, buffer, "00005");766 767 time.tm_hour = 23;768 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01I", &time);769 EXPECT_STREQ_LEN(written, buffer, "11");770 771 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02I", &time);772 EXPECT_STREQ_LEN(written, buffer, "11");773 774 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05I", &time);775 EXPECT_STREQ_LEN(written, buffer, "00011");776}777 778TEST(LlvmLibcStrftimeTest, DayOfYear) {779 // this tests %j, which reads: [tm_yday]780 struct tm time;781 char buffer[100];782 size_t written = 0;783 SimplePaddedNum spn;784 785 // Tests on all the well defined values786 for (int i = 0; i < LIBC_NAMESPACE::time_constants::DAYS_PER_LEAP_YEAR; ++i) {787 time.tm_yday = i;788 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%j", &time);789 char *result = spn.get_padded_num(i + 1, 3);790 791 ASSERT_STREQ(buffer, result);792 ASSERT_EQ(written, spn.get_str_len());793 }794 795 // padding is technically undefined for this conversion, but we support it, so796 // we need to test it.797 time.tm_yday = 5 - 1;798 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01j", &time);799 EXPECT_STREQ_LEN(written, buffer, "5");800 801 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02j", &time);802 EXPECT_STREQ_LEN(written, buffer, "05");803 804 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05j", &time);805 EXPECT_STREQ_LEN(written, buffer, "00005");806 807 time.tm_yday = 123 - 1;808 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01j", &time);809 EXPECT_STREQ_LEN(written, buffer, "123");810 811 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02j", &time);812 EXPECT_STREQ_LEN(written, buffer, "123");813 814 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05j", &time);815 EXPECT_STREQ_LEN(written, buffer, "00123");816}817 818TEST(LlvmLibcStrftimeTest, MonthOfYear) {819 // this tests %m, which reads: [tm_mon]820 struct tm time;821 char buffer[100];822 size_t written = 0;823 SimplePaddedNum spn;824 825 // Tests on all the well defined values826 for (int i = 0; i < LIBC_NAMESPACE::time_constants::MONTHS_PER_YEAR; ++i) {827 time.tm_mon = i;828 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%m", &time);829 // %m is 1 indexed, so add 1 to the number we're comparing to.830 char *result = spn.get_padded_num(i + 1, 2);831 832 ASSERT_STREQ(buffer, result);833 ASSERT_EQ(written, spn.get_str_len());834 }835 836 // padding is technically undefined for this conversion, but we support it, so837 // we need to test it.838 time.tm_mon = 5 - 1;839 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01m", &time);840 EXPECT_STREQ_LEN(written, buffer, "5");841 842 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02m", &time);843 EXPECT_STREQ_LEN(written, buffer, "05");844 845 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05m", &time);846 EXPECT_STREQ_LEN(written, buffer, "00005");847 848 time.tm_mon = 11 - 1;849 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01m", &time);850 EXPECT_STREQ_LEN(written, buffer, "11");851 852 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02m", &time);853 EXPECT_STREQ_LEN(written, buffer, "11");854 855 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05m", &time);856 EXPECT_STREQ_LEN(written, buffer, "00011");857}858 859TEST(LlvmLibcStrftimeTest, MinuteOfHour) {860 // this tests %M, which reads: [tm_min]861 struct tm time;862 char buffer[100];863 size_t written = 0;864 SimplePaddedNum spn;865 866 // Tests on all the well defined values867 for (int i = 0; i < LIBC_NAMESPACE::time_constants::MINUTES_PER_HOUR; ++i) {868 time.tm_min = i;869 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%M", &time);870 char *result = spn.get_padded_num(i, 2);871 872 ASSERT_STREQ(buffer, result);873 ASSERT_EQ(written, spn.get_str_len());874 }875 876 // padding is technically undefined for this conversion, but we support it, so877 // we need to test it.878 time.tm_min = 5;879 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01M", &time);880 EXPECT_STREQ_LEN(written, buffer, "5");881 882 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02M", &time);883 EXPECT_STREQ_LEN(written, buffer, "05");884 885 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05M", &time);886 EXPECT_STREQ_LEN(written, buffer, "00005");887 888 time.tm_min = 11;889 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01M", &time);890 EXPECT_STREQ_LEN(written, buffer, "11");891 892 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02M", &time);893 EXPECT_STREQ_LEN(written, buffer, "11");894 895 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05M", &time);896 EXPECT_STREQ_LEN(written, buffer, "00011");897}898 899TEST(LlvmLibcStrftimeTest, SecondsSinceEpoch) {900 // this tests %s, which reads: [tm_year, tm_mon, tm_mday, tm_hour, tm_min,901 // tm_sec, tm_isdst]902 struct tm time;903 char buffer[100];904 size_t written = 0;905 906 time.tm_year = get_adjusted_year(1970);907 // yday is not used, the day of the year is calculated from the month and mday908 time.tm_mon = 0;909 time.tm_mday = 1; // the only 1-indexed member910 time.tm_hour = 0;911 time.tm_min = 0;912 time.tm_sec = 1;913 time.tm_isdst = 0;914 915 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%s", &time);916 EXPECT_STREQ_LEN(written, buffer, "1");917 918 // The time as of writing this test919 time.tm_year = get_adjusted_year(2025);920 time.tm_mon = 1;921 time.tm_mday = 4;922 time.tm_hour = 11;923 time.tm_min = 8;924 time.tm_sec = 41;925 time.tm_isdst = 0;926 927 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%s", &time);928 // if you run your system's strftime to compare you will likely get a slightly929 // different result because it's supposed to respect timezones.930 EXPECT_STREQ_LEN(written, buffer, "1738667321");931 932 // Thorough testing of the mktime mechanism is done in the mktime tests, so933 // they aren't duplicated here.934 935 // padding is technically undefined for this conversion, but we support it, so936 // we need to test it.937 time.tm_year = get_adjusted_year(1970);938 time.tm_mon = 0;939 time.tm_mday = 1;940 time.tm_hour = 0;941 time.tm_min = 0;942 time.tm_sec = 5;943 time.tm_isdst = 0;944 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01s", &time);945 EXPECT_STREQ_LEN(written, buffer, "5");946 947 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02s", &time);948 EXPECT_STREQ_LEN(written, buffer, "05");949 950 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05s", &time);951 EXPECT_STREQ_LEN(written, buffer, "00005");952 953 time.tm_min = 11;954 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01s", &time);955 EXPECT_STREQ_LEN(written, buffer, "665");956 957 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02s", &time);958 EXPECT_STREQ_LEN(written, buffer, "665");959 960 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05s", &time);961 EXPECT_STREQ_LEN(written, buffer, "00665");962}963 964TEST(LlvmLibcStrftimeTest, SecondOfMinute) {965 // this tests %S, which reads: [tm_sec]966 struct tm time;967 char buffer[100];968 size_t written = 0;969 SimplePaddedNum spn;970 971 // Tests on all the well defined values972 for (int i = 0; i < LIBC_NAMESPACE::time_constants::SECONDS_PER_MIN; ++i) {973 time.tm_sec = i;974 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%S", &time);975 char *result = spn.get_padded_num(i, 2);976 977 ASSERT_STREQ(buffer, result);978 ASSERT_EQ(written, spn.get_str_len());979 }980 981 // padding is technically undefined for this conversion, but we support it, so982 // we need to test it.983 time.tm_sec = 5;984 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01S", &time);985 EXPECT_STREQ_LEN(written, buffer, "5");986 987 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02S", &time);988 EXPECT_STREQ_LEN(written, buffer, "05");989 990 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05S", &time);991 EXPECT_STREQ_LEN(written, buffer, "00005");992 993 time.tm_sec = 11;994 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01S", &time);995 EXPECT_STREQ_LEN(written, buffer, "11");996 997 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02S", &time);998 EXPECT_STREQ_LEN(written, buffer, "11");999 1000 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05S", &time);1001 EXPECT_STREQ_LEN(written, buffer, "00011");1002}1003 1004TEST(LlvmLibcStrftimeTest, ISODayOfWeek) {1005 // this tests %u, which reads: [tm_wday]1006 struct tm time;1007 char buffer[100];1008 size_t written = 0;1009 SimplePaddedNum spn;1010 1011 time.tm_wday = LIBC_NAMESPACE::time_constants::SUNDAY;1012 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%u", &time);1013 EXPECT_STREQ_LEN(written, buffer, "7");1014 1015 // Tests on all the well defined values except for sunday, which is 0 in1016 // normal weekdays but 7 here.1017 for (int i = LIBC_NAMESPACE::time_constants::MONDAY;1018 i <= LIBC_NAMESPACE::time_constants::SATURDAY; ++i) {1019 time.tm_wday = i;1020 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%u", &time);1021 char *result = spn.get_padded_num(i, 1);1022 1023 ASSERT_STREQ(buffer, result);1024 ASSERT_EQ(written, spn.get_str_len());1025 }1026 1027 // padding is technically undefined for this conversion, but we support it, so1028 // we need to test it.1029 time.tm_wday = 5;1030 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01u", &time);1031 EXPECT_STREQ_LEN(written, buffer, "5");1032 1033 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02u", &time);1034 EXPECT_STREQ_LEN(written, buffer, "05");1035 1036 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05u", &time);1037 EXPECT_STREQ_LEN(written, buffer, "00005");1038}1039 1040TEST(LlvmLibcStrftimeTest, WeekOfYearStartingSunday) {1041 // this tests %U, which reads: [tm_year, tm_wday, tm_yday]1042 struct tm time;1043 char buffer[100];1044 size_t written = 0;1045 SimplePaddedNum spn;1046 1047 // setting the year to a leap year, but it doesn't actually matter. This1048 // conversion doesn't end up checking the year at all.1049 time.tm_year = get_adjusted_year(2000);1050 1051 const int WEEK_START = LIBC_NAMESPACE::time_constants::SUNDAY;1052 1053 for (int first_weekday = LIBC_NAMESPACE::time_constants::SUNDAY;1054 first_weekday <= LIBC_NAMESPACE::time_constants::SATURDAY;1055 ++first_weekday) {1056 time.tm_wday = first_weekday;1057 int cur_week = 0;1058 1059 // iterate through the year, starting on first_weekday.1060 for (int yday = 0;1061 yday < LIBC_NAMESPACE::time_constants::DAYS_PER_LEAP_YEAR; ++yday) {1062 time.tm_yday = yday;1063 // If the week just ended, move to the next week.1064 if (time.tm_wday == WEEK_START)1065 ++cur_week;1066 1067 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%U", &time);1068 char *result = spn.get_padded_num(cur_week, 2);1069 1070 ASSERT_STREQ(buffer, result);1071 ASSERT_EQ(written, spn.get_str_len());1072 1073 // a day has passed, move to the next weekday, looping as necessary.1074 time.tm_wday =1075 (time.tm_wday + 1) % LIBC_NAMESPACE::time_constants::DAYS_PER_WEEK;1076 }1077 }1078 1079 // padding is technically undefined for this conversion, but we support it, so1080 // we need to test it.1081 time.tm_wday = LIBC_NAMESPACE::time_constants::SUNDAY;1082 time.tm_yday = 22;1083 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01U", &time);1084 EXPECT_STREQ_LEN(written, buffer, "4");1085 1086 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02U", &time);1087 EXPECT_STREQ_LEN(written, buffer, "04");1088 1089 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05U", &time);1090 EXPECT_STREQ_LEN(written, buffer, "00004");1091 1092 time.tm_wday = LIBC_NAMESPACE::time_constants::SUNDAY;1093 time.tm_yday = 78;1094 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01U", &time);1095 EXPECT_STREQ_LEN(written, buffer, "12");1096 1097 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02U", &time);1098 EXPECT_STREQ_LEN(written, buffer, "12");1099 1100 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05U", &time);1101 EXPECT_STREQ_LEN(written, buffer, "00012");1102}1103 1104TEST(LlvmLibcStrftimeTest, ISOWeekOfYear) {1105 // this tests %V, which reads: [tm_year, tm_wday, tm_yday]1106 struct tm time;1107 char buffer[100];1108 size_t written = 0;1109 SimplePaddedNum spn;1110 1111 const int starting_year = get_adjusted_year(1999);1112 1113 // we're going to check the days from 1999 to 2001 to cover all the1114 // transitions to and from leap years and non-leap years (the start of 19991115 // and end of 2001 cover the non-leap years).1116 const int days_to_check = // 10961117 LIBC_NAMESPACE::time_constants::DAYS_PER_NON_LEAP_YEAR +1118 LIBC_NAMESPACE::time_constants::DAYS_PER_LEAP_YEAR +1119 LIBC_NAMESPACE::time_constants::DAYS_PER_NON_LEAP_YEAR;1120 1121 const int WEEK_START = LIBC_NAMESPACE::time_constants::MONDAY;1122 1123 for (int first_weekday = LIBC_NAMESPACE::time_constants::SUNDAY;1124 first_weekday <= LIBC_NAMESPACE::time_constants::SATURDAY;1125 ++first_weekday) {1126 time.tm_year = starting_year;1127 time.tm_wday = first_weekday;1128 time.tm_yday = 0;1129 int cur_week = 1;1130 if (first_weekday == LIBC_NAMESPACE::time_constants::SUNDAY ||1131 first_weekday == LIBC_NAMESPACE::time_constants::SATURDAY)1132 cur_week = 52;1133 else if (first_weekday == LIBC_NAMESPACE::time_constants::FRIDAY)1134 cur_week = 53;1135 1136 // iterate through the year, starting on first_weekday.1137 for (size_t cur_day = 0; cur_day < days_to_check; ++cur_day) {1138 // If the week just ended, move to the next week.1139 1140 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%V", &time);1141 char *result = spn.get_padded_num(cur_week, 2);1142 1143 ASSERT_STREQ(buffer, result);1144 ASSERT_EQ(written, spn.get_str_len());1145 1146 // a day has passed, increment the counters.1147 ++time.tm_yday;1148 if (time.tm_yday ==1149 (time.tm_year == get_adjusted_year(2000)1150 ? LIBC_NAMESPACE::time_constants::DAYS_PER_LEAP_YEAR1151 : LIBC_NAMESPACE::time_constants::DAYS_PER_NON_LEAP_YEAR)) {1152 time.tm_yday = 0;1153 ++time.tm_year;1154 }1155 1156 time.tm_wday =1157 (time.tm_wday + 1) % LIBC_NAMESPACE::time_constants::DAYS_PER_WEEK;1158 if (time.tm_wday == WEEK_START) {1159 ++cur_week;1160 const int days_left_in_year =1161 (time.tm_year == get_adjusted_year(2000)1162 ? LIBC_NAMESPACE::time_constants::LAST_DAY_OF_LEAP_YEAR1163 : LIBC_NAMESPACE::time_constants::LAST_DAY_OF_NON_LEAP_YEAR) -1164 time.tm_yday;1165 1166 // if the week we're currently in is in the next year, or if the year1167 // has turned over, reset the week.1168 if (days_left_in_year < 3 || (cur_week > 51 && time.tm_yday < 10))1169 cur_week = 1;1170 }1171 }1172 }1173 1174 // padding is technically undefined for this conversion, but we support it, so1175 // we need to test it.1176 time.tm_wday = LIBC_NAMESPACE::time_constants::SUNDAY;1177 time.tm_yday = 22;1178 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01U", &time);1179 EXPECT_STREQ_LEN(written, buffer, "4");1180 1181 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02U", &time);1182 EXPECT_STREQ_LEN(written, buffer, "04");1183 1184 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05U", &time);1185 EXPECT_STREQ_LEN(written, buffer, "00004");1186 1187 time.tm_wday = LIBC_NAMESPACE::time_constants::SUNDAY;1188 time.tm_yday = 78;1189 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01U", &time);1190 EXPECT_STREQ_LEN(written, buffer, "12");1191 1192 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02U", &time);1193 EXPECT_STREQ_LEN(written, buffer, "12");1194 1195 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05U", &time);1196 EXPECT_STREQ_LEN(written, buffer, "00012");1197}1198 1199TEST(LlvmLibcStrftimeTest, DayOfWeek) {1200 // this tests %w, which reads: [tm_wday]1201 struct tm time;1202 char buffer[100];1203 size_t written = 0;1204 SimplePaddedNum spn;1205 1206 // Tests on all the well defined values.1207 for (int i = LIBC_NAMESPACE::time_constants::SUNDAY;1208 i <= LIBC_NAMESPACE::time_constants::SATURDAY; ++i) {1209 time.tm_wday = i;1210 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%w", &time);1211 char *result = spn.get_padded_num(i, 1);1212 1213 ASSERT_STREQ(buffer, result);1214 ASSERT_EQ(written, spn.get_str_len());1215 }1216 1217 // padding is technically undefined for this conversion, but we support it, so1218 // we need to test it.1219 time.tm_wday = 5;1220 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01w", &time);1221 EXPECT_STREQ_LEN(written, buffer, "5");1222 1223 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02w", &time);1224 EXPECT_STREQ_LEN(written, buffer, "05");1225 1226 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05w", &time);1227 EXPECT_STREQ_LEN(written, buffer, "00005");1228}1229 1230TEST(LlvmLibcStrftimeTest, WeekOfYearStartingMonday) {1231 // this tests %W, which reads: [tm_year, tm_wday, tm_yday]1232 struct tm time;1233 char buffer[100];1234 size_t written = 0;1235 SimplePaddedNum spn;1236 1237 // setting the year to a leap year, but it doesn't actually matter. This1238 // conversion doesn't end up checking the year at all.1239 time.tm_year = get_adjusted_year(2000);1240 1241 const int WEEK_START = LIBC_NAMESPACE::time_constants::MONDAY;1242 1243 for (int first_weekday = LIBC_NAMESPACE::time_constants::SUNDAY;1244 first_weekday <= LIBC_NAMESPACE::time_constants::SATURDAY;1245 ++first_weekday) {1246 time.tm_wday = first_weekday;1247 int cur_week = 0;1248 1249 // iterate through the year, starting on first_weekday.1250 for (int yday = 0;1251 yday < LIBC_NAMESPACE::time_constants::DAYS_PER_LEAP_YEAR; ++yday) {1252 time.tm_yday = yday;1253 // If the week just ended, move to the next week.1254 if (time.tm_wday == WEEK_START)1255 ++cur_week;1256 1257 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%W", &time);1258 char *result = spn.get_padded_num(cur_week, 2);1259 1260 ASSERT_STREQ(buffer, result);1261 ASSERT_EQ(written, spn.get_str_len());1262 1263 // a day has passed, move to the next weekday, looping as necessary.1264 time.tm_wday =1265 (time.tm_wday + 1) % LIBC_NAMESPACE::time_constants::DAYS_PER_WEEK;1266 }1267 }1268 1269 // padding is technically undefined for this conversion, but we support it, so1270 // we need to test it.1271 time.tm_wday = LIBC_NAMESPACE::time_constants::MONDAY;1272 time.tm_yday = 22;1273 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01W", &time);1274 EXPECT_STREQ_LEN(written, buffer, "4");1275 1276 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02W", &time);1277 EXPECT_STREQ_LEN(written, buffer, "04");1278 1279 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05W", &time);1280 EXPECT_STREQ_LEN(written, buffer, "00004");1281 1282 time.tm_wday = LIBC_NAMESPACE::time_constants::MONDAY;1283 time.tm_yday = 78;1284 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01W", &time);1285 EXPECT_STREQ_LEN(written, buffer, "12");1286 1287 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02W", &time);1288 EXPECT_STREQ_LEN(written, buffer, "12");1289 1290 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05W", &time);1291 EXPECT_STREQ_LEN(written, buffer, "00012");1292}1293 1294TEST(LlvmLibcStrftimeTest, YearOfCentury) {1295 // this tests %y, which reads: [tm_year]1296 struct tm time;1297 char buffer[100];1298 size_t written = 0;1299 SimplePaddedNum spn;1300 1301 time.tm_year = get_adjusted_year(2000);1302 1303 // iterate through the year, starting on first_weekday.1304 for (int year = 1900; year < 2001; ++year) {1305 time.tm_year = get_adjusted_year(year);1306 1307 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%y", &time);1308 char *result = spn.get_padded_num(year % 100, 2);1309 1310 ASSERT_STREQ(buffer, result);1311 ASSERT_EQ(written, spn.get_str_len());1312 }1313 1314 // padding is technically undefined for this conversion, but we support it, so1315 // we need to test it.1316 time.tm_year = get_adjusted_year(2004);1317 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01y", &time);1318 EXPECT_STREQ_LEN(written, buffer, "4");1319 1320 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02y", &time);1321 EXPECT_STREQ_LEN(written, buffer, "04");1322 1323 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05y", &time);1324 EXPECT_STREQ_LEN(written, buffer, "00004");1325 1326 time.tm_year = get_adjusted_year(12345);1327 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01y", &time);1328 EXPECT_STREQ_LEN(written, buffer, "45");1329 1330 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%02y", &time);1331 EXPECT_STREQ_LEN(written, buffer, "45");1332 1333 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05y", &time);1334 EXPECT_STREQ_LEN(written, buffer, "00045");1335}1336 1337TEST(LlvmLibcStrftimeTest, FullYearTests) {1338 // this tests %Y, which reads: [tm_year]1339 struct tm time;1340 char buffer[100];1341 size_t written = 0;1342 SimplePaddedNum spn;1343 1344 // Test the easy cases1345 for (int i = 1; i < 10000; ++i) {1346 time.tm_year = get_adjusted_year(i);1347 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%Y", &time);1348 char *result = spn.get_padded_num(i, 4);1349 1350 ASSERT_STREQ(buffer, result);1351 ASSERT_EQ(written, spn.get_str_len());1352 }1353 1354 time.tm_year = get_adjusted_year(11900);1355 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%Y", &time);1356 EXPECT_STREQ_LEN(written, buffer, "11900");1357 1358 time.tm_year = get_adjusted_year(0);1359 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%Y", &time);1360 EXPECT_STREQ_LEN(written, buffer, "0000");1361 1362 time.tm_year = get_adjusted_year(-1);1363 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%Y", &time);1364 // TODO: should this be what we standardize? Posix doesn't specify what to do1365 // about negative numbers1366 EXPECT_STREQ_LEN(written, buffer, "-001");1367 1368 time.tm_year = get_adjusted_year(-9001);1369 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%Y", &time);1370 EXPECT_STREQ_LEN(written, buffer, "-9001");1371 1372 time.tm_year = get_adjusted_year(-10001);1373 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%Y", &time);1374 EXPECT_STREQ_LEN(written, buffer, "-10001");1375 1376 // width tests (with the 0 flag, since the default padding is undefined).1377 time.tm_year = get_adjusted_year(2023);1378 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01Y", &time);1379 EXPECT_STREQ_LEN(written, buffer, "2023");1380 1381 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%04Y", &time);1382 EXPECT_STREQ_LEN(written, buffer, "2023");1383 1384 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05Y", &time);1385 EXPECT_STREQ_LEN(written, buffer, "02023");1386 1387 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%010Y", &time);1388 EXPECT_STREQ_LEN(written, buffer, "0000002023");1389 1390 time.tm_year = get_adjusted_year(900);1391 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01Y", &time);1392 EXPECT_STREQ_LEN(written, buffer, "900");1393 1394 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%04Y", &time);1395 EXPECT_STREQ_LEN(written, buffer, "0900");1396 1397 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05Y", &time);1398 EXPECT_STREQ_LEN(written, buffer, "00900");1399 1400 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%010Y", &time);1401 EXPECT_STREQ_LEN(written, buffer, "0000000900");1402 1403 time.tm_year = get_adjusted_year(12345);1404 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01Y", &time);1405 EXPECT_STREQ_LEN(written, buffer, "12345");1406 1407 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%04Y", &time);1408 EXPECT_STREQ_LEN(written, buffer, "12345");1409 1410 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05Y", &time);1411 EXPECT_STREQ_LEN(written, buffer, "12345");1412 1413 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%010Y", &time);1414 EXPECT_STREQ_LEN(written, buffer, "0000012345");1415 1416 time.tm_year = get_adjusted_year(-123);1417 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01Y", &time);1418 EXPECT_STREQ_LEN(written, buffer, "-123");1419 1420 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%04Y", &time);1421 EXPECT_STREQ_LEN(written, buffer, "-123");1422 1423 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05Y", &time);1424 EXPECT_STREQ_LEN(written, buffer, "-0123");1425 1426 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%010Y", &time);1427 EXPECT_STREQ_LEN(written, buffer, "-000000123");1428 1429 // '+' flag tests1430 time.tm_year = get_adjusted_year(2023);1431 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+1Y", &time);1432 EXPECT_STREQ_LEN(written, buffer, "2023");1433 1434 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+4Y", &time);1435 EXPECT_STREQ_LEN(written, buffer, "2023");1436 1437 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+5Y", &time);1438 EXPECT_STREQ_LEN(written, buffer, "+2023");1439 1440 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+10Y", &time);1441 EXPECT_STREQ_LEN(written, buffer, "+000002023");1442 1443 time.tm_year = get_adjusted_year(900);1444 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+1Y", &time);1445 EXPECT_STREQ_LEN(written, buffer, "900");1446 1447 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+4Y", &time);1448 EXPECT_STREQ_LEN(written, buffer, "0900");1449 1450 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+5Y", &time);1451 EXPECT_STREQ_LEN(written, buffer, "+0900");1452 1453 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+10Y", &time);1454 EXPECT_STREQ_LEN(written, buffer, "+000000900");1455 1456 time.tm_year = get_adjusted_year(12345);1457 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+1Y", &time);1458 EXPECT_STREQ_LEN(written, buffer, "+12345");1459 1460 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+4Y", &time);1461 EXPECT_STREQ_LEN(written, buffer, "+12345");1462 1463 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+5Y", &time);1464 EXPECT_STREQ_LEN(written, buffer, "+12345");1465 1466 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+10Y", &time);1467 EXPECT_STREQ_LEN(written, buffer, "+000012345");1468 1469 time.tm_year = get_adjusted_year(-123);1470 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+1Y", &time);1471 EXPECT_STREQ_LEN(written, buffer, "-123");1472 1473 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+4Y", &time);1474 EXPECT_STREQ_LEN(written, buffer, "-123");1475 1476 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+5Y", &time);1477 EXPECT_STREQ_LEN(written, buffer, "-0123");1478 1479 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+10Y", &time);1480 EXPECT_STREQ_LEN(written, buffer, "-000000123");1481 1482 // Posix specified tests:1483 time.tm_year = get_adjusted_year(1970);1484 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%Y", &time);1485 EXPECT_STREQ_LEN(written, buffer, "1970");1486 1487 time.tm_year = get_adjusted_year(1970);1488 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+4Y", &time);1489 EXPECT_STREQ_LEN(written, buffer, "1970");1490 1491 time.tm_year = get_adjusted_year(27);1492 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%Y", &time);1493 EXPECT_STREQ_LEN(written, buffer, "0027");1494 1495 time.tm_year = get_adjusted_year(270);1496 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%Y", &time);1497 EXPECT_STREQ_LEN(written, buffer, "0270");1498 1499 time.tm_year = get_adjusted_year(270);1500 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+4Y", &time);1501 EXPECT_STREQ_LEN(written, buffer, "0270");1502 1503 time.tm_year = get_adjusted_year(12345);1504 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%Y", &time);1505 EXPECT_STREQ_LEN(written, buffer, "12345");1506 1507 time.tm_year = get_adjusted_year(12345);1508 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+4Y", &time);1509 EXPECT_STREQ_LEN(written, buffer, "+12345");1510 1511 time.tm_year = get_adjusted_year(12345);1512 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05Y", &time);1513 EXPECT_STREQ_LEN(written, buffer, "12345");1514 1515 time.tm_year = get_adjusted_year(270);1516 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+5Y", &time);1517 EXPECT_STREQ_LEN(written, buffer, "+0270");1518 1519 time.tm_year = get_adjusted_year(12345);1520 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+5Y", &time);1521 EXPECT_STREQ_LEN(written, buffer, "+12345");1522 1523 time.tm_year = get_adjusted_year(12345);1524 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%06Y", &time);1525 EXPECT_STREQ_LEN(written, buffer, "012345");1526 1527 time.tm_year = get_adjusted_year(12345);1528 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+6Y", &time);1529 EXPECT_STREQ_LEN(written, buffer, "+12345");1530 1531 time.tm_year = get_adjusted_year(123456);1532 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%08Y", &time);1533 EXPECT_STREQ_LEN(written, buffer, "00123456");1534 1535 time.tm_year = get_adjusted_year(123456);1536 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+8Y", &time);1537 EXPECT_STREQ_LEN(written, buffer, "+0123456");1538}1539 1540// String conversions1541 1542struct num_str_pair {1543 int num;1544 LIBC_NAMESPACE::cpp::string_view str;1545};1546 1547TEST(LlvmLibcStrftimeTest, ShortWeekdayName) {1548 // this tests %a, which reads: [tm_wday]1549 struct tm time;1550 char buffer[100];1551 size_t written = 0;1552 1553 constexpr LIBC_NAMESPACE::cpp::array<1554 num_str_pair, LIBC_NAMESPACE::time_constants::DAYS_PER_WEEK>1555 WEEKDAY_PAIRS = {{1556 {LIBC_NAMESPACE::time_constants::SUNDAY, "Sun"},1557 {LIBC_NAMESPACE::time_constants::MONDAY, "Mon"},1558 {LIBC_NAMESPACE::time_constants::TUESDAY, "Tue"},1559 {LIBC_NAMESPACE::time_constants::WEDNESDAY, "Wed"},1560 {LIBC_NAMESPACE::time_constants::THURSDAY, "Thu"},1561 {LIBC_NAMESPACE::time_constants::FRIDAY, "Fri"},1562 {LIBC_NAMESPACE::time_constants::SATURDAY, "Sat"},1563 }};1564 1565 for (size_t i = 0; i < WEEKDAY_PAIRS.size(); ++i) {1566 time.tm_wday = WEEKDAY_PAIRS[i].num;1567 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%a", &time);1568 EXPECT_STREQ(buffer, WEEKDAY_PAIRS[i].str.data());1569 EXPECT_EQ(written, WEEKDAY_PAIRS[i].str.size());1570 }1571 1572 // check invalid weekdays1573 time.tm_wday = -1;1574 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%a", &time);1575 EXPECT_STREQ_LEN(written, buffer, "?");1576 1577 time.tm_wday = LIBC_NAMESPACE::time_constants::SATURDAY + 1;1578 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%a", &time);1579 EXPECT_STREQ_LEN(written, buffer, "?");1580 1581 // padding is technically undefined for this conversion, but we support it, so1582 // we need to test it.1583 time.tm_wday = LIBC_NAMESPACE::time_constants::THURSDAY;1584 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%1a", &time);1585 EXPECT_STREQ_LEN(written, buffer, "Thu");1586 1587 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%3a", &time);1588 EXPECT_STREQ_LEN(written, buffer, "Thu");1589 1590 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%10a", &time);1591 EXPECT_STREQ_LEN(written, buffer, " Thu");1592 1593 time.tm_wday = -1;1594 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%1a", &time);1595 EXPECT_STREQ_LEN(written, buffer, "?");1596 1597 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%3a", &time);1598 EXPECT_STREQ_LEN(written, buffer, " ?");1599 1600 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%10a", &time);1601 EXPECT_STREQ_LEN(written, buffer, " ?");1602}1603 1604TEST(LlvmLibcStrftimeTest, FullWeekdayName) {1605 // this tests %a, which reads: [tm_wday]1606 struct tm time;1607 char buffer[100];1608 size_t written = 0;1609 1610 constexpr LIBC_NAMESPACE::cpp::array<1611 num_str_pair, LIBC_NAMESPACE::time_constants::DAYS_PER_WEEK>1612 WEEKDAY_PAIRS = {{1613 {LIBC_NAMESPACE::time_constants::SUNDAY, "Sunday"},1614 {LIBC_NAMESPACE::time_constants::MONDAY, "Monday"},1615 {LIBC_NAMESPACE::time_constants::TUESDAY, "Tuesday"},1616 {LIBC_NAMESPACE::time_constants::WEDNESDAY, "Wednesday"},1617 {LIBC_NAMESPACE::time_constants::THURSDAY, "Thursday"},1618 {LIBC_NAMESPACE::time_constants::FRIDAY, "Friday"},1619 {LIBC_NAMESPACE::time_constants::SATURDAY, "Saturday"},1620 }};1621 1622 for (size_t i = 0; i < WEEKDAY_PAIRS.size(); ++i) {1623 time.tm_wday = WEEKDAY_PAIRS[i].num;1624 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%A", &time);1625 EXPECT_STREQ(buffer, WEEKDAY_PAIRS[i].str.data());1626 EXPECT_EQ(written, WEEKDAY_PAIRS[i].str.size());1627 }1628 1629 // check invalid weekdays1630 time.tm_wday = -1;1631 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%A", &time);1632 EXPECT_STREQ_LEN(written, buffer, "?");1633 1634 time.tm_wday = LIBC_NAMESPACE::time_constants::SATURDAY + 1;1635 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%A", &time);1636 EXPECT_STREQ_LEN(written, buffer, "?");1637 1638 // padding is technically undefined for this conversion, but we support it, so1639 // we need to test it.1640 time.tm_wday = LIBC_NAMESPACE::time_constants::THURSDAY;1641 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%1A", &time);1642 EXPECT_STREQ_LEN(written, buffer, "Thursday");1643 1644 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%3A", &time);1645 EXPECT_STREQ_LEN(written, buffer, "Thursday");1646 1647 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%10A", &time);1648 EXPECT_STREQ_LEN(written, buffer, " Thursday");1649 1650 time.tm_wday = -1;1651 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%1A", &time);1652 EXPECT_STREQ_LEN(written, buffer, "?");1653 1654 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%3A", &time);1655 EXPECT_STREQ_LEN(written, buffer, " ?");1656 1657 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%10A", &time);1658 EXPECT_STREQ_LEN(written, buffer, " ?");1659}1660 1661TEST(LlvmLibcStrftimeTest, ShortMonthName) {1662 // this tests %b, which reads: [tm_mon]1663 struct tm time;1664 char buffer[100];1665 size_t written = 0;1666 1667 constexpr LIBC_NAMESPACE::cpp::array<1668 num_str_pair, LIBC_NAMESPACE::time_constants::MONTHS_PER_YEAR>1669 MONTH_PAIRS = {{1670 {LIBC_NAMESPACE::time_constants::JANUARY, "Jan"},1671 {LIBC_NAMESPACE::time_constants::FEBRUARY, "Feb"},1672 {LIBC_NAMESPACE::time_constants::MARCH, "Mar"},1673 {LIBC_NAMESPACE::time_constants::APRIL, "Apr"},1674 {LIBC_NAMESPACE::time_constants::MAY, "May"},1675 {LIBC_NAMESPACE::time_constants::JUNE, "Jun"},1676 {LIBC_NAMESPACE::time_constants::JULY, "Jul"},1677 {LIBC_NAMESPACE::time_constants::AUGUST, "Aug"},1678 {LIBC_NAMESPACE::time_constants::SEPTEMBER, "Sep"},1679 {LIBC_NAMESPACE::time_constants::OCTOBER, "Oct"},1680 {LIBC_NAMESPACE::time_constants::NOVEMBER, "Nov"},1681 {LIBC_NAMESPACE::time_constants::DECEMBER, "Dec"},1682 }};1683 1684 for (size_t i = 0; i < MONTH_PAIRS.size(); ++i) {1685 time.tm_mon = MONTH_PAIRS[i].num;1686 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%b", &time);1687 EXPECT_STREQ(buffer, MONTH_PAIRS[i].str.data());1688 EXPECT_EQ(written, MONTH_PAIRS[i].str.size());1689 }1690 1691 // check invalid weekdays1692 time.tm_mon = -1;1693 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%b", &time);1694 EXPECT_STREQ_LEN(written, buffer, "?");1695 1696 time.tm_mon = LIBC_NAMESPACE::time_constants::DECEMBER + 1;1697 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%b", &time);1698 EXPECT_STREQ_LEN(written, buffer, "?");1699 1700 // Also test %h, which is identical to %b1701 time.tm_mon = LIBC_NAMESPACE::time_constants::OCTOBER;1702 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%h", &time);1703 EXPECT_STREQ_LEN(written, buffer, "Oct");1704 1705 // padding is technically undefined for this conversion, but we support it, so1706 // we need to test it.1707 time.tm_mon = LIBC_NAMESPACE::time_constants::OCTOBER;1708 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%1b", &time);1709 EXPECT_STREQ_LEN(written, buffer, "Oct");1710 1711 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%3b", &time);1712 EXPECT_STREQ_LEN(written, buffer, "Oct");1713 1714 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%10b", &time);1715 EXPECT_STREQ_LEN(written, buffer, " Oct");1716 1717 time.tm_mon = -1;1718 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%1b", &time);1719 EXPECT_STREQ_LEN(written, buffer, "?");1720 1721 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%3b", &time);1722 EXPECT_STREQ_LEN(written, buffer, " ?");1723 1724 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%10b", &time);1725 EXPECT_STREQ_LEN(written, buffer, " ?");1726}1727 1728TEST(LlvmLibcStrftimeTest, FullMonthName) {1729 // this tests %B, which reads: [tm_mon]1730 struct tm time;1731 char buffer[100];1732 size_t written = 0;1733 1734 constexpr LIBC_NAMESPACE::cpp::array<1735 num_str_pair, LIBC_NAMESPACE::time_constants::MONTHS_PER_YEAR>1736 MONTH_PAIRS = {{1737 {LIBC_NAMESPACE::time_constants::JANUARY, "January"},1738 {LIBC_NAMESPACE::time_constants::FEBRUARY, "February"},1739 {LIBC_NAMESPACE::time_constants::MARCH, "March"},1740 {LIBC_NAMESPACE::time_constants::APRIL, "April"},1741 {LIBC_NAMESPACE::time_constants::MAY, "May"},1742 {LIBC_NAMESPACE::time_constants::JUNE, "June"},1743 {LIBC_NAMESPACE::time_constants::JULY, "July"},1744 {LIBC_NAMESPACE::time_constants::AUGUST, "August"},1745 {LIBC_NAMESPACE::time_constants::SEPTEMBER, "September"},1746 {LIBC_NAMESPACE::time_constants::OCTOBER, "October"},1747 {LIBC_NAMESPACE::time_constants::NOVEMBER, "November"},1748 {LIBC_NAMESPACE::time_constants::DECEMBER, "December"},1749 }};1750 1751 for (size_t i = 0; i < MONTH_PAIRS.size(); ++i) {1752 time.tm_mon = MONTH_PAIRS[i].num;1753 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%B", &time);1754 EXPECT_STREQ(buffer, MONTH_PAIRS[i].str.data());1755 EXPECT_EQ(written, MONTH_PAIRS[i].str.size());1756 }1757 1758 // check invalid weekdays1759 time.tm_mon = -1;1760 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%B", &time);1761 EXPECT_STREQ_LEN(written, buffer, "?");1762 1763 time.tm_mon = LIBC_NAMESPACE::time_constants::DECEMBER + 1;1764 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%B", &time);1765 EXPECT_STREQ_LEN(written, buffer, "?");1766 1767 // padding is technically undefined for this conversion, but we support it, so1768 // we need to test it.1769 time.tm_mon = LIBC_NAMESPACE::time_constants::OCTOBER;1770 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%1B", &time);1771 EXPECT_STREQ_LEN(written, buffer, "October");1772 1773 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%3B", &time);1774 EXPECT_STREQ_LEN(written, buffer, "October");1775 1776 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%10B", &time);1777 EXPECT_STREQ_LEN(written, buffer, " October");1778 1779 time.tm_mon = -1;1780 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%1B", &time);1781 EXPECT_STREQ_LEN(written, buffer, "?");1782 1783 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%3B", &time);1784 EXPECT_STREQ_LEN(written, buffer, " ?");1785 1786 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%10B", &time);1787 EXPECT_STREQ_LEN(written, buffer, " ?");1788}1789 1790TEST(LlvmLibcStrftimeTest, AM_PM) {1791 // this tests %p, which reads: [tm_hour]1792 struct tm time;1793 char buffer[100];1794 size_t written = 0;1795 1796 time.tm_hour = 0;1797 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%p", &time);1798 EXPECT_STREQ_LEN(written, buffer, "AM");1799 1800 time.tm_hour = 6;1801 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%p", &time);1802 EXPECT_STREQ_LEN(written, buffer, "AM");1803 1804 time.tm_hour = 12;1805 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%p", &time);1806 EXPECT_STREQ_LEN(written, buffer, "PM");1807 1808 time.tm_hour = 18;1809 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%p", &time);1810 EXPECT_STREQ_LEN(written, buffer, "PM");1811 1812 // padding is technically undefined for this conversion, but we support it, so1813 // we need to test it.1814 time.tm_hour = 6;1815 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%1p", &time);1816 EXPECT_STREQ_LEN(written, buffer, "AM");1817 1818 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%2p", &time);1819 EXPECT_STREQ_LEN(written, buffer, "AM");1820 1821 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%10p", &time);1822 EXPECT_STREQ_LEN(written, buffer, " AM");1823 1824 time.tm_hour = 18;1825 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%1p", &time);1826 EXPECT_STREQ_LEN(written, buffer, "PM");1827 1828 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%2p", &time);1829 EXPECT_STREQ_LEN(written, buffer, "PM");1830 1831 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%10p", &time);1832 EXPECT_STREQ_LEN(written, buffer, " PM");1833}1834 1835TEST(LlvmLibcStrftimeTest, DateFormatUS) {1836 // this tests %D, which reads: [tm_mon, tm_mday, tm_year]1837 // This is equivalent to "%m/%d/%y"1838 struct tm time;1839 char buffer[100];1840 size_t written = 0;1841 1842 // each of %m, %d, and %y have their own tests, so this test won't cover all1843 // values of those. Instead it will do basic tests and focus on the specific1844 // padding behavior.1845 1846 time.tm_mon = 0; // 0 indexed, so 0 is january1847 time.tm_mday = 2; // 1 indexed, so 2 is the 2nd1848 time.tm_year = get_adjusted_year(1903);1849 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%D", &time);1850 EXPECT_STREQ_LEN(written, buffer, "01/02/03");1851 1852 time.tm_mon = 11;1853 time.tm_mday = 31;1854 time.tm_year = get_adjusted_year(1999);1855 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%D", &time);1856 EXPECT_STREQ_LEN(written, buffer, "12/31/99");1857 1858 // The day LLVM-libc started1859 time.tm_mon = 8;1860 time.tm_mday = 16;1861 time.tm_year = get_adjusted_year(2019);1862 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%D", &time);1863 EXPECT_STREQ_LEN(written, buffer, "09/16/19");1864 1865 // %x is equivalent to %D in default locale1866 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%x", &time);1867 EXPECT_STREQ_LEN(written, buffer, "09/16/19");1868 1869 // padding is technically undefined for this conversion, but we support it, so1870 // we need to test it.1871 // Padding is handled in the same way as POSIX describes for %F1872 time.tm_mon = 1;1873 time.tm_mday = 5;1874 time.tm_year = get_adjusted_year(2025);1875 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01D", &time);1876 EXPECT_STREQ_LEN(written, buffer, "2/05/25");1877 1878 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%07D", &time);1879 EXPECT_STREQ_LEN(written, buffer, "2/05/25");1880 1881 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%010D", &time);1882 EXPECT_STREQ_LEN(written, buffer, "0002/05/25");1883 1884 time.tm_mon = 9;1885 time.tm_mday = 2;1886 time.tm_year = get_adjusted_year(2000);1887 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01D", &time);1888 EXPECT_STREQ_LEN(written, buffer, "10/02/00");1889 1890 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%07D", &time);1891 EXPECT_STREQ_LEN(written, buffer, "10/02/00");1892 1893 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%010D", &time);1894 EXPECT_STREQ_LEN(written, buffer, "0010/02/00");1895}1896 1897TEST(LlvmLibcStrftimeTest, DateFormatISO) {1898 // this tests %F, which reads: [tm_year, tm_mon, tm_mday]1899 // This is equivalent to "%Y-%m-%d"1900 struct tm time;1901 char buffer[100];1902 size_t written = 0;1903 1904 // each of %Y, %m, and %d have their own tests, so this test won't cover all1905 // values of those. Instead it will do basic tests and focus on the specific1906 // padding behavior.1907 1908 time.tm_year = get_adjusted_year(1901);1909 time.tm_mon = 1; // 0 indexed, so 1 is february1910 time.tm_mday = 3; // 1 indexed, so 2 is the 2nd1911 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%F", &time);1912 EXPECT_STREQ_LEN(written, buffer, "1901-02-03");1913 1914 time.tm_year = get_adjusted_year(1999);1915 time.tm_mon = 11;1916 time.tm_mday = 31;1917 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%F", &time);1918 EXPECT_STREQ_LEN(written, buffer, "1999-12-31");1919 1920 time.tm_year = get_adjusted_year(2019);1921 time.tm_mon = 8;1922 time.tm_mday = 16;1923 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%F", &time);1924 EXPECT_STREQ_LEN(written, buffer, "2019-09-16");1925 1926 time.tm_year = get_adjusted_year(123);1927 time.tm_mon = 3;1928 time.tm_mday = 5;1929 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%F", &time);1930 EXPECT_STREQ_LEN(written, buffer, "0123-04-05");1931 1932 time.tm_year = get_adjusted_year(67);1933 time.tm_mon = 7;1934 time.tm_mday = 9;1935 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%F", &time);1936 EXPECT_STREQ_LEN(written, buffer, "0067-08-09");1937 1938 time.tm_year = get_adjusted_year(2);1939 time.tm_mon = 1;1940 time.tm_mday = 14;1941 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%F", &time);1942 EXPECT_STREQ_LEN(written, buffer, "0002-02-14");1943 1944 time.tm_year = get_adjusted_year(-543);1945 time.tm_mon = 1;1946 time.tm_mday = 1;1947 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%F", &time);1948 EXPECT_STREQ_LEN(written, buffer, "-543-02-01");1949 1950 // padding tests1951 time.tm_year = get_adjusted_year(2025);1952 time.tm_mon = 1;1953 time.tm_mday = 5;1954 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01F", &time);1955 EXPECT_STREQ_LEN(written, buffer, "2025-02-05");1956 1957 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%010F", &time);1958 EXPECT_STREQ_LEN(written, buffer, "2025-02-05");1959 1960 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%012F", &time);1961 EXPECT_STREQ_LEN(written, buffer, "002025-02-05");1962 1963 time.tm_year = get_adjusted_year(12345);1964 time.tm_mon = 11;1965 time.tm_mday = 25;1966 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01F", &time);1967 EXPECT_STREQ_LEN(written, buffer, "12345-12-25");1968 1969 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%010F", &time);1970 EXPECT_STREQ_LEN(written, buffer, "12345-12-25");1971 1972 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%012F", &time);1973 EXPECT_STREQ_LEN(written, buffer, "012345-12-25");1974 1975 time.tm_year = get_adjusted_year(476);1976 time.tm_mon = 8;1977 time.tm_mday = 4;1978 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01F", &time);1979 EXPECT_STREQ_LEN(written, buffer, "476-09-04");1980 1981 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%010F", &time);1982 EXPECT_STREQ_LEN(written, buffer, "0476-09-04");1983 1984 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%012F", &time);1985 EXPECT_STREQ_LEN(written, buffer, "000476-09-04");1986 1987 time.tm_year = get_adjusted_year(-100);1988 time.tm_mon = 9;1989 time.tm_mday = 31;1990 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01F", &time);1991 EXPECT_STREQ_LEN(written, buffer, "-100-10-31");1992 1993 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%010F", &time);1994 EXPECT_STREQ_LEN(written, buffer, "-100-10-31");1995 1996 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%012F", &time);1997 EXPECT_STREQ_LEN(written, buffer, "-00100-10-31");1998 1999 // '+' flag tests2000 time.tm_year = get_adjusted_year(2025);2001 time.tm_mon = 1;2002 time.tm_mday = 5;2003 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+1F", &time);2004 EXPECT_STREQ_LEN(written, buffer, "2025-02-05");2005 2006 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+10F", &time);2007 EXPECT_STREQ_LEN(written, buffer, "2025-02-05");2008 2009 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+12F", &time);2010 EXPECT_STREQ_LEN(written, buffer, "+02025-02-05");2011 2012 time.tm_year = get_adjusted_year(12345);2013 time.tm_mon = 11;2014 time.tm_mday = 25;2015 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+1F", &time);2016 EXPECT_STREQ_LEN(written, buffer, "+12345-12-25");2017 2018 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+10F", &time);2019 EXPECT_STREQ_LEN(written, buffer, "+12345-12-25");2020 2021 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+12F", &time);2022 EXPECT_STREQ_LEN(written, buffer, "+12345-12-25");2023 2024 time.tm_year = get_adjusted_year(476);2025 time.tm_mon = 8;2026 time.tm_mday = 4;2027 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+1F", &time);2028 EXPECT_STREQ_LEN(written, buffer, "476-09-04");2029 2030 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+10F", &time);2031 EXPECT_STREQ_LEN(written, buffer, "0476-09-04");2032 2033 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+12F", &time);2034 EXPECT_STREQ_LEN(written, buffer, "+00476-09-04");2035 2036 time.tm_year = get_adjusted_year(-100);2037 time.tm_mon = 9;2038 time.tm_mday = 31;2039 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+1F", &time);2040 EXPECT_STREQ_LEN(written, buffer, "-100-10-31");2041 2042 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+10F", &time);2043 EXPECT_STREQ_LEN(written, buffer, "-100-10-31");2044 2045 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%+12F", &time);2046 EXPECT_STREQ_LEN(written, buffer, "-00100-10-31");2047}2048 2049TEST(LlvmLibcStrftimeTest, TimeFormatAMPM) {2050 // this tests %r, which reads: [tm_hour, tm_min, tm_sec]2051 // This is equivalent to "%I:%M:%S %p"2052 struct tm time;2053 char buffer[100];2054 size_t written = 0;2055 2056 // each of %I, %M, %S, and %p have their own tests, so this test won't cover2057 // all values of those. Instead it will do basic tests and focus on the2058 // specific padding behavior.2059 2060 time.tm_hour = 0;2061 time.tm_min = 0;2062 time.tm_sec = 0;2063 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%r", &time);2064 EXPECT_STREQ_LEN(written, buffer, "12:00:00 AM");2065 2066 time.tm_hour = 1;2067 time.tm_min = 23;2068 time.tm_sec = 45;2069 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%r", &time);2070 EXPECT_STREQ_LEN(written, buffer, "01:23:45 AM");2071 2072 time.tm_hour = 18;2073 time.tm_min = 6;2074 time.tm_sec = 2;2075 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%r", &time);2076 EXPECT_STREQ_LEN(written, buffer, "06:06:02 PM");2077 2078 // padding is technically undefined for this conversion, but we support it, so2079 // we need to test it.2080 // Padding is handled in the same way as POSIX describes for %F2081 time.tm_hour = 10;2082 time.tm_min = 9;2083 time.tm_sec = 59;2084 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01r", &time);2085 EXPECT_STREQ_LEN(written, buffer, "10:09:59 AM");2086 2087 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%011r", &time);2088 EXPECT_STREQ_LEN(written, buffer, "10:09:59 AM");2089 2090 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%013r", &time);2091 EXPECT_STREQ_LEN(written, buffer, "0010:09:59 AM");2092 2093 time.tm_hour = 16;2094 time.tm_min = 56;2095 time.tm_sec = 9;2096 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01r", &time);2097 EXPECT_STREQ_LEN(written, buffer, "4:56:09 PM");2098 2099 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%011r", &time);2100 EXPECT_STREQ_LEN(written, buffer, "04:56:09 PM");2101 2102 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%013r", &time);2103 EXPECT_STREQ_LEN(written, buffer, "0004:56:09 PM");2104}2105 2106TEST(LlvmLibcStrftimeTest, TimeFormatMinute) {2107 // this tests %R, which reads: [tm_hour, tm_min]2108 // This is equivalent to "%H:%M"2109 struct tm time;2110 char buffer[100];2111 size_t written = 0;2112 2113 // each of %H and %M have their own tests, so this test won't cover2114 // all values of those. Instead it will do basic tests and focus on the2115 // specific padding behavior.2116 2117 time.tm_hour = 0;2118 time.tm_min = 0;2119 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%R", &time);2120 EXPECT_STREQ_LEN(written, buffer, "00:00");2121 2122 time.tm_hour = 1;2123 time.tm_min = 23;2124 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%R", &time);2125 EXPECT_STREQ_LEN(written, buffer, "01:23");2126 2127 time.tm_hour = 18;2128 time.tm_min = 6;2129 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%R", &time);2130 EXPECT_STREQ_LEN(written, buffer, "18:06");2131 2132 // padding is technically undefined for this conversion, but we support it, so2133 // we need to test it.2134 // Padding is handled in the same way as POSIX describes for %F2135 time.tm_hour = 10;2136 time.tm_min = 9;2137 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01R", &time);2138 EXPECT_STREQ_LEN(written, buffer, "10:09");2139 2140 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05R", &time);2141 EXPECT_STREQ_LEN(written, buffer, "10:09");2142 2143 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%07R", &time);2144 EXPECT_STREQ_LEN(written, buffer, "0010:09");2145 2146 time.tm_hour = 4;2147 time.tm_min = 56;2148 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01R", &time);2149 EXPECT_STREQ_LEN(written, buffer, "4:56");2150 2151 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%05R", &time);2152 EXPECT_STREQ_LEN(written, buffer, "04:56");2153 2154 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%07R", &time);2155 EXPECT_STREQ_LEN(written, buffer, "0004:56");2156}2157 2158TEST(LlvmLibcStrftimeTest, TimeFormatSecond) {2159 // this tests %T, which reads: [tm_hour, tm_min, tm_sec]2160 // This is equivalent to "%H:%M:%S"2161 struct tm time;2162 char buffer[100];2163 size_t written = 0;2164 2165 // each of %H, %M, and %S have their own tests, so this test won't cover2166 // all values of those. Instead it will do basic tests and focus on the2167 // specific padding behavior.2168 2169 time.tm_hour = 0;2170 time.tm_min = 0;2171 time.tm_sec = 0;2172 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%T", &time);2173 EXPECT_STREQ_LEN(written, buffer, "00:00:00");2174 2175 time.tm_hour = 1;2176 time.tm_min = 23;2177 time.tm_sec = 45;2178 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%T", &time);2179 EXPECT_STREQ_LEN(written, buffer, "01:23:45");2180 2181 time.tm_hour = 18;2182 time.tm_min = 6;2183 time.tm_sec = 2;2184 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%T", &time);2185 EXPECT_STREQ_LEN(written, buffer, "18:06:02");2186 2187 // %X is equivalent to %T in default locale2188 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%X", &time);2189 EXPECT_STREQ_LEN(written, buffer, "18:06:02");2190 2191 // padding is technically undefined for this conversion, but we support it, so2192 // we need to test it.2193 // Padding is handled in the same way as POSIX describes for %F2194 time.tm_hour = 10;2195 time.tm_min = 9;2196 time.tm_sec = 59;2197 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01T", &time);2198 EXPECT_STREQ_LEN(written, buffer, "10:09:59");2199 2200 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%08T", &time);2201 EXPECT_STREQ_LEN(written, buffer, "10:09:59");2202 2203 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%010T", &time);2204 EXPECT_STREQ_LEN(written, buffer, "0010:09:59");2205 2206 time.tm_hour = 4;2207 time.tm_min = 56;2208 time.tm_sec = 9;2209 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%01T", &time);2210 EXPECT_STREQ_LEN(written, buffer, "4:56:09");2211 2212 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%08T", &time);2213 EXPECT_STREQ_LEN(written, buffer, "04:56:09");2214 2215 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%010T", &time);2216 EXPECT_STREQ_LEN(written, buffer, "0004:56:09");2217}2218 2219TEST(LlvmLibcStrftimeTest, TimeFormatFullDateTime) {2220 // this tests %c, which reads:2221 // [tm_wday, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_year]2222 // This is equivalent to "%a %b %e %T %Y"2223 struct tm time;2224 char buffer[100];2225 size_t written = 0;2226 2227 // each of the individual conversions have their own tests, so this test won't2228 // cover all values of those. Instead it will do basic tests and focus on the2229 // specific padding behavior.2230 2231 time.tm_wday = 0;2232 time.tm_mon = 0;2233 time.tm_mday = 1;2234 time.tm_hour = 0;2235 time.tm_min = 0;2236 time.tm_sec = 0;2237 time.tm_year = get_adjusted_year(1900);2238 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%c", &time);2239 EXPECT_STREQ_LEN(written, buffer, "Sun Jan 1 00:00:00 1900");2240 2241 time.tm_wday = 3;2242 time.tm_mon = 5;2243 time.tm_mday = 15;2244 time.tm_hour = 14;2245 time.tm_min = 13;2246 time.tm_sec = 12;2247 time.tm_year = get_adjusted_year(2011);2248 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%c", &time);2249 EXPECT_STREQ_LEN(written, buffer, "Wed Jun 15 14:13:12 2011");2250 2251 // now, as of the writing of this test2252 time.tm_wday = 4;2253 time.tm_mon = 1;2254 time.tm_mday = 6;2255 time.tm_hour = 12;2256 time.tm_min = 57;2257 time.tm_sec = 50;2258 time.tm_year = get_adjusted_year(2025);2259 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%c", &time);2260 EXPECT_STREQ_LEN(written, buffer, "Thu Feb 6 12:57:50 2025");2261 2262 time.tm_wday = 5;2263 time.tm_mon = 8;2264 time.tm_mday = 4;2265 time.tm_hour = 16;2266 time.tm_min = 57;2267 time.tm_sec = 18;2268 time.tm_year = get_adjusted_year(476);2269 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%c", &time);2270 EXPECT_STREQ_LEN(written, buffer, "Fri Sep 4 16:57:18 0476");2271 2272 // padding is technically undefined for this conversion, but we support it, so2273 // we need to test it.2274 // Padding is handled in the same way as POSIX describes for %F.2275 // This includes assuming the trailing conversions are of a fixed width, which2276 // isn't true for years. For simplicity, we format years (%Y) to be padded to2277 // 4 digits when possible, which means padding will work as expected for years2278 // -999 to 9999. If the current year is large enough to trigger this bug,2279 // congrats on making it another ~8000 years!2280 time.tm_wday = 5;2281 time.tm_mon = 8;2282 time.tm_mday = 4;2283 time.tm_hour = 16;2284 time.tm_min = 57;2285 time.tm_sec = 18;2286 time.tm_year = get_adjusted_year(476);2287 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%1c", &time);2288 EXPECT_STREQ_LEN(written, buffer, "Fri Sep 4 16:57:18 0476");2289 2290 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%24c", &time);2291 EXPECT_STREQ_LEN(written, buffer, "Fri Sep 4 16:57:18 0476");2292 2293 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%26c", &time);2294 EXPECT_STREQ_LEN(written, buffer, " Fri Sep 4 16:57:18 0476");2295 2296 // '0' flag has no effect on the string part of the conversion, only the2297 // numbers, and the only one of those that defaults to spaces is day of month.2298 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%026c", &time);2299 EXPECT_STREQ_LEN(written, buffer, " Fri Sep 04 16:57:18 0476");2300 2301 time.tm_wday = 3;2302 time.tm_mon = 5;2303 time.tm_mday = 15;2304 time.tm_hour = 14;2305 time.tm_min = 13;2306 time.tm_sec = 12;2307 time.tm_year = get_adjusted_year(2011);2308 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%1c", &time);2309 EXPECT_STREQ_LEN(written, buffer, "Wed Jun 15 14:13:12 2011");2310 2311 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%24c", &time);2312 EXPECT_STREQ_LEN(written, buffer, "Wed Jun 15 14:13:12 2011");2313 2314 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%26c", &time);2315 EXPECT_STREQ_LEN(written, buffer, " Wed Jun 15 14:13:12 2011");2316 2317 written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%026c", &time);2318 EXPECT_STREQ_LEN(written, buffer, " Wed Jun 15 14:13:12 2011");2319}2320 2321// TODO: implement %z and %Z when timezones are implemented.2322// TEST(LlvmLibcStrftimeTest, TimezoneOffset) {2323// // this tests %z, which reads: [tm_isdst, tm_zone]2324// struct tm time;2325// char buffer[100];2326// size_t written = 0;2327// SimplePaddedNum spn;2328// }2329 2330TEST(LlvmLibcStrftimeTest, BufferTooSmall) {2331 struct tm time;2332 char tiny_buffer[1];2333 2334 time.tm_year = get_adjusted_year(2025);2335 time.tm_mon = 10;2336 time.tm_mday = 24;2337 2338 size_t written =2339 LIBC_NAMESPACE::strftime(tiny_buffer, sizeof(tiny_buffer), "%F", &time);2340 EXPECT_EQ(written, size_t{0});2341 2342 char small_buffer[10];2343 2344 // The string "2025-11-24" is 10 chars,2345 // so strftime needs 10 + 1 bytes to write the string and the null terminator.2346 written =2347 LIBC_NAMESPACE::strftime(small_buffer, sizeof(small_buffer), "%F", &time);2348 EXPECT_EQ(written, size_t{0});2349}2350