LibC: Make mktime() and timegm() handle years before 1970

And also years that don't fit in 32-bit.

Lovingly tested via LibJS's Date.UTC(), which happens to call
timegm().
This commit is contained in:
Nico Weber 2020-08-21 22:17:18 -04:00 committed by Andreas Kling
parent 96891669c3
commit c399caf27f
Notes: sideshowbarker 2024-07-19 03:18:55 +09:00
2 changed files with 30 additions and 6 deletions

View file

@ -93,21 +93,28 @@ static void time_to_tm(struct tm* tm, time_t t)
tm->tm_mday += days;
}
static time_t tm_to_time(struct tm* tm, long timezone_adjust)
static time_t tm_to_time(struct tm* tm, long timezone_adjust_seconds)
{
int days = 0;
int seconds = tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec;
for (int year = 70; year < tm->tm_year; ++year)
days += 365 + __is_leap_year(1900 + year);
if (tm->tm_year >= 70) {
for (int year = 70; year < tm->tm_year; ++year)
days += 365 + __is_leap_year(1900 + year);
} else {
for (int year = tm->tm_year; year < 70; ++year)
days -= 365 + __is_leap_year(1900 + year);
}
tm->tm_yday = tm->tm_mday - 1;
// FIXME: What if tm->tm_mon < 0 or tm->tm_mon > 12?
for (int month = 0; month < tm->tm_mon; ++month)
tm->tm_yday += __days_per_month[month];
if (tm->tm_mon > 1 && __is_leap_year(1900 + tm->tm_year))
++tm->tm_yday;
days += tm->tm_yday;
return days * __seconds_per_day + seconds + timezone_adjust;
int seconds = tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec;
return static_cast<time_t>(days) * __seconds_per_day + seconds + timezone_adjust_seconds;
}
time_t mktime(struct tm* tm)

View file

@ -1,5 +1,4 @@
test("basic functionality", () => {
// FIXME: Years before 1970 don't work. Once they do, add a test. Also add a test with a year before 1900 then.
expect(Date.UTC(2020)).toBe(1577836800000);
expect(Date.UTC(2000, 10)).toBe(973036800000);
expect(Date.UTC(1980, 5, 30)).toBe(331171200000);
@ -7,4 +6,22 @@ test("basic functionality", () => {
expect(Date.UTC(1970, 5, 30, 13, 30)).toBe(15600600000);
expect(Date.UTC(1970, 0, 1, 0, 0, 59)).toBe(59000);
expect(Date.UTC(1970, 0, 1, 0, 0, 0, 999)).toBe(999);
expect(Date.UTC(1969, 11, 31, 23, 59, 59, 817)).toBe(-183);
expect(Date.UTC(1799, 0)).toBe(-5396198400000);
expect(Date.UTC(1800, 0)).toBe(-5364662400000);
expect(Date.UTC(1801, 0)).toBe(-5333126400000);
expect(Date.UTC(1802, 0)).toBe(-5301590400000);
expect(Date.UTC(1803, 0)).toBe(-5270054400000);
expect(Date.UTC(1804, 0)).toBe(-5238518400000);
expect(Date.UTC(1999, 0)).toBe(915148800000);
expect(Date.UTC(2000, 0)).toBe(946684800000);
expect(Date.UTC(2001, 0)).toBe(978307200000);
expect(Date.UTC(2002, 0)).toBe(1009843200000);
expect(Date.UTC(2003, 0)).toBe(1041379200000);
expect(Date.UTC(2004, 0)).toBe(1072915200000);
expect(Date.UTC(20000, 0)).toBe(568971820800000);
});