brintos

brintos / llvm-project-archived public Read only

0
0
Text · 85.7 KiB · 5222152 Raw
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