commit c715d4030343260c37b064df864a91ec1064a13b
parent 999d029a5b062ef4ceb1e7e145eaa1c41e4bfcc5
Author: Roberto E. Vargas Caballero <k0ga@shike2.net>
Date: Sun, 19 Apr 2026 20:55:58 +0200
libc/time: Support negative time values
Diffstat:
2 files changed, 44 insertions(+), 18 deletions(-)
diff --git a/src/libc/time/gmtime.c b/src/libc/time/gmtime.c
@@ -1,3 +1,4 @@
+#include <stdlib.h>
#include <time.h>
#include "../libc.h"
@@ -7,28 +8,45 @@
struct tm *
gmtime(const time_t *tim)
{
+ div_t d;
+ int month, year;
+ time_t tday, day, t = *tim;
static struct tm tm;
- time_t day;
- int i;
- tm.tm_sec = *tim % SECDAY;
- tm.tm_min = tm.tm_sec / 60;
- tm.tm_sec %= 60;
- tm.tm_hour = tm.tm_min / 60;
- tm.tm_min %= 60;
- day = *tim / SECDAY;
+ day = t / SECDAY;
+ tday = t % SECDAY;
+ if (tday < 0) {
+ tday += SECDAY;
+ day--;
+ }
- tm.tm_wday = (day + THU) % 7; /* 1/1/1970 was Thursday */
+ d = div(tday, 60);
+ tm.tm_sec = d.rem;
- for (i = EPOCH; day >= _daysyear(i); ++i)
- day -= _daysyear(i);
- tm.tm_year = i - 1900;
+ d = div(d.quot, 60);
+ tm.tm_min = d.rem;
+
+ tm.tm_hour = d.quot;
+
+ /* 1/1/1970 was Thursday */
+ tm.tm_wday = (day + THU) % 7;
+
+ year = EPOCH;
+ if (day >= 0) {
+ while (day >= _daysyear(year))
+ day -= _daysyear(year++);
+ } else {
+ while (day < 0)
+ day += _daysyear(--year);
+ }
+
+ tm.tm_year = year - 1900;
tm.tm_yday = day;
- _daysmon[FEB] = FEBDAYS(i);
- for (i = JAN; day >= _daysmon[i]; i++)
- day -= _daysmon[i];
- tm.tm_mon = i;
+ _daysmon[FEB] = FEBDAYS(year);
+ for (month = JAN; day >= _daysmon[month]; month++)
+ day -= _daysmon[month];
+ tm.tm_mon = month;
tm.tm_mday = day + 1;
tm.tm_isdst = 0;
diff --git a/src/libc/time/mktime.c b/src/libc/time/mktime.c
@@ -110,8 +110,15 @@ mktime(struct tm *tm)
t = 0;
year = tm->tm_year + BASEYEAR;
- for (i = EPOCH; i < year; ++i)
- t += _daysyear(i) * SECDAY;
+
+ if (year >= EPOCH) {
+ for (i = EPOCH; i < year; ++i)
+ t += _daysyear(i) * SECDAY;
+ } else {
+ for (i = EPOCH; i > year; --i)
+ t -= _daysyear(i) * SECDAY;
+ }
+
for (i = 0; i < tm->tm_mon; ++i)
t += _daysmon[i] * SECDAY;
@@ -119,6 +126,7 @@ mktime(struct tm *tm)
t += tm->tm_min * SECMIN;
t += tm->tm_hour * SECHOUR;
t += (tm->tm_mday-1) * SECDAY;
+
aux = localtime(&t);
if (tm->tm_isdst == -1)