scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | Submodules | README | LICENSE

commit 59a8cce85e45329b3f0eece6b734686313bfb81a
parent 30e021c6f5621382cffb390b75e6dce9a042a906
Author: Roberto E. Vargas Caballero <k0ga@shike2.net>
Date:   Thu, 16 Apr 2026 10:55:06 +0200

libc/time: Allow negative years in mktime()

We support years before 1900, and it means that tm_year can be a negative
number. This also means that we have to separate what is the base year
used in mktime() and the minimum year that we can represent.

Diffstat:
Minclude/scc/bits/darwin/amd64/arch/time.h | 3++-
Minclude/scc/bits/dragonfly/amd64/arch/time.h | 3++-
Minclude/scc/bits/freebsd/amd64/arch/time.h | 3++-
Minclude/scc/bits/linux/amd64/arch/time.h | 3++-
Minclude/scc/bits/linux/arm/arch/time.h | 1+
Minclude/scc/bits/linux/arm64/arch/time.h | 3++-
Minclude/scc/bits/linux/i386/arch/time.h | 1+
Minclude/scc/bits/linux/ppc/arch/time.h | 1+
Minclude/scc/bits/netbsd/amd64/arch/time.h | 3++-
Minclude/scc/bits/openbsd/amd64/arch/time.h | 3++-
Msrc/libc/libc.h | 2+-
Msrc/libc/time/mktime.c | 23++++++++++++-----------
12 files changed, 30 insertions(+), 19 deletions(-)

diff --git a/include/scc/bits/darwin/amd64/arch/time.h b/include/scc/bits/darwin/amd64/arch/time.h @@ -1,4 +1,5 @@ -#define _MAXYEAR 9999 +#define _MAXYEAR 99999 +#define _MINYEAR -99999 typedef long time_t; typedef long clock_t; diff --git a/include/scc/bits/dragonfly/amd64/arch/time.h b/include/scc/bits/dragonfly/amd64/arch/time.h @@ -1,4 +1,5 @@ -#define _MAXYEAR 9999 +#define _MAXYEAR 99999 +#define _MINYEAR -99999 typedef long time_t; typedef long clock_t; diff --git a/include/scc/bits/freebsd/amd64/arch/time.h b/include/scc/bits/freebsd/amd64/arch/time.h @@ -1,4 +1,5 @@ -#define _MAXYEAR 9999 +#define _MAXYEAR 99999 +#define _MINYEAR -99999 typedef long time_t; typedef long clock_t; diff --git a/include/scc/bits/linux/amd64/arch/time.h b/include/scc/bits/linux/amd64/arch/time.h @@ -1,4 +1,5 @@ -#define _MAXYEAR 9999 +#define _MAXYEAR 99999 +#define _MINYEAR -99999 typedef long time_t; typedef long clock_t; diff --git a/include/scc/bits/linux/arm/arch/time.h b/include/scc/bits/linux/arm/arch/time.h @@ -1,4 +1,5 @@ #define _MAXYEAR 2038 +#define _MINYEAR 1902 typedef long time_t; typedef long clock_t; diff --git a/include/scc/bits/linux/arm64/arch/time.h b/include/scc/bits/linux/arm64/arch/time.h @@ -1,4 +1,5 @@ -#define _MAXYEAR 9999 +#define _MAXYEAR 99999 +#define _MINYEAR -99999 typedef long time_t; typedef long clock_t; diff --git a/include/scc/bits/linux/i386/arch/time.h b/include/scc/bits/linux/i386/arch/time.h @@ -1,4 +1,5 @@ #define _MAXYEAR 2038 +#define _MINYEAR 1902 typedef long time_t; typedef long clock_t; diff --git a/include/scc/bits/linux/ppc/arch/time.h b/include/scc/bits/linux/ppc/arch/time.h @@ -1,4 +1,5 @@ #define _MAXYEAR 2038 +#define _MINYEAR 1902 typedef long time_t; typedef long clock_t; diff --git a/include/scc/bits/netbsd/amd64/arch/time.h b/include/scc/bits/netbsd/amd64/arch/time.h @@ -1,4 +1,5 @@ -#define _MAXYEAR 9999 +#define _MAXYEAR 99999 +#define _MINYEAR -99999 typedef long time_t; typedef long clock_t; diff --git a/include/scc/bits/openbsd/amd64/arch/time.h b/include/scc/bits/openbsd/amd64/arch/time.h @@ -1,4 +1,5 @@ -#define _MAXYEAR 9999 +#define _MAXYEAR 99999 +#define _MINYEAR -99999 typedef long time_t; typedef long clock_t; diff --git a/src/libc/libc.h b/src/libc/libc.h @@ -28,7 +28,7 @@ enum { #define FEBDAYS(y) ((_daysyear(y) == 366) ? 29 : 28) #define EPOCH 1970 -#define MINYEAR 1900 +#define BASEYEAR 1900 #define SECMIN 60 #define SECHOUR (60 * SECMIN) /* 3600 */ #define SECDAY (24 * SECHOUR) /* 86400 */ diff --git a/src/libc/time/mktime.c b/src/libc/time/mktime.c @@ -47,15 +47,9 @@ normalize(struct tm *tm) || !norm(&tm->tm_mon, &tm->tm_year, 12)) return 0; - if (tm->tm_year < 0) - return 0; - day = tm->tm_mday; yday = 0; - year = MINYEAR + tm->tm_year; - - if (year > _MAXYEAR) - return 0; + year = BASEYEAR + tm->tm_year; _daysmon[FEB] = FEBDAYS(year); @@ -65,7 +59,7 @@ normalize(struct tm *tm) */ for (mon = tm->tm_mon; day < 1; --mon) { if (mon == JAN) { - if (year == MINYEAR) + if (year == INT_MIN) return 0; year--; _daysmon[FEB] = FEBDAYS(year); @@ -77,7 +71,7 @@ normalize(struct tm *tm) for (; day > _daysmon[mon]; ++mon) { day -= _daysmon[mon]; if (mon == DEC) { - if (year == _MAXYEAR) + if (year == INT_MAX) return 0; year++; _daysmon[FEB] = FEBDAYS(year); @@ -85,11 +79,18 @@ normalize(struct tm *tm) } } + if (year < INT_MIN + BASEYEAR) + return 0; + year -= BASEYEAR; + + if (year > _MAXYEAR || year < _MINYEAR) + return 0; + for (int i = 0; i < mon; ++i) yday += _daysmon[i]; tm->tm_mon = mon; - tm->tm_year = year - MINYEAR; + tm->tm_year = year; tm->tm_mday = day; tm->tm_yday = yday + day - 1; tm->tm_wday = (_newyear(tm->tm_year) + tm->tm_yday) % 7; @@ -107,7 +108,7 @@ mktime(struct tm *tm) if (!normalize(tm)) return -1; - year = tm->tm_year + MINYEAR; + year = tm->tm_year + BASEYEAR; for (i = EPOCH; i < year; ++i) t += _daysyear(i) * SECDAY;