Merge pull request #4099 from yunusshaikh7/fix/libc-asctime-years-before-1900-windows

fix(libc): format years before 1900 in asctime on Windows
This commit is contained in:
Dean 2026-10-13 01:28:18 +13:00 committed by GitHub
commit 256cc9f976
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 29 additions and 2 deletions

View File

@ -17,6 +17,9 @@
namespace {
constexpr const char* WEEKDAY_NAMES[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
constexpr const char* MONTH_NAMES[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
constexpr std::size_t ASCTIME_SIZE = sizeof("Sun Jan-2147483648 -2147483648:-2147483648:-2147483648 -2147483648\n");
constexpr std::int64_t SECONDS_PER_DAY = 86400;
constexpr std::int64_t DAYS_FROM_MARCH_TO_YEAR_END = 306;
@ -324,8 +327,12 @@ size_t APS5_VABI libc_strftime_nid_postfix(char* str, size_t count, const char*
}
char* APS5_VABI asctime_nid_postfix(const GuestTm* timeptr) {
const std::tm host = toHostTm(*timeptr);
return std::asctime(&host);
static thread_local char result[ASCTIME_SIZE];
const char* weekday = timeptr->tm_wday >= 0 && timeptr->tm_wday < 7 ? WEEKDAY_NAMES[timeptr->tm_wday] : "???";
const char* month = timeptr->tm_mon >= 0 && timeptr->tm_mon < 12 ? MONTH_NAMES[timeptr->tm_mon] : "???";
std::snprintf(result, sizeof(result), "%s %s%3d %.2d:%.2d:%.2d %lld\n", weekday, month, timeptr->tm_mday,
timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec, 1900LL + timeptr->tm_year);
return result;
}
char* APS5_VABI ctime_nid_postfix(const int64_t* timer) {

View File

@ -19,6 +19,7 @@ GuestTm* APS5_VABI libc_localtime_nid_postfix(const std::int64_t*);
GuestTm* APS5_VABI localtime_nid_postfix(const std::int64_t*);
GuestTm* APS5_VABI gmtime_s_nid_postfix(const std::int64_t*, GuestTm*);
GuestTm* APS5_VABI localtime_s_nid_postfix(const std::int64_t*, GuestTm*);
char* APS5_VABI asctime_nid_postfix(const GuestTm*);
std::int64_t APS5_VABI mktime_nid_postfix(GuestTm*);
std::size_t APS5_VABI strftime_nid_postfix(char*, std::size_t, const char*, const GuestTm*);
void APS5_VABI tzset_nid_postfix(void);
@ -68,6 +69,17 @@ static void CheckConcurrent(Converter convert, BufferedConverter buffered, const
Require(convert(&invalid) == nullptr, "Unrepresentable time was accepted");
}
static GuestTm UtcTime(std::int64_t timer) {
GuestTm utc{};
Require(gmtime_s_nid_postfix(&timer, &utc) == &utc, "UTC conversion failed");
return utc;
}
static void CheckAsctime(const GuestTm& brokenDown, const char* expected) {
const char* text = asctime_nid_postfix(&brokenDown);
Require(text != nullptr && std::strcmp(text, expected) == 0, "asctime did not format the broken-down time");
}
struct UtcCase {
std::int64_t timer;
int year;
@ -249,6 +261,14 @@ int main() {
GuestTm scratch{};
Require(gmtime_s_nid_postfix(&underflow, &scratch) == nullptr, "Unrepresentable negative time was accepted");
CheckAsctime(UtcTime(0), "Thu Jan 1 00:00:00 1970\n");
CheckAsctime(UtcTime(-2208988801), "Sun Dec 31 23:59:59 1899\n");
CheckAsctime(UtcTime(-30610224000), "Wed Jan 1 00:00:00 1000\n");
GuestTm pastMonthEnd = UtcTime(983404800);
pastMonthEnd.tm_mon = 1;
pastMonthEnd.tm_mday = 29;
CheckAsctime(pastMonthEnd, "Thu Feb 29 00:00:00 2001\n");
const std::int64_t epoch = 0;
GuestTm local{};
std::memset(&local, 0xAA, sizeof(local));