scc

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

commit f717073ae1c23b90b63645014a35a9bf2bb4198a
parent 98f4b5fba82c6fc1d7b110c84dbaf3dd0cf171d5
Author: Roberto E. Vargas Caballero <k0ga@shike2.net>
Date:   Tue, 21 Apr 2026 10:01:00 +0200

libc/time: Set tm_isdst in mktime() output

The C spec is a bit unclear about how mktime() has to behave with the tm_isdst
value, opening the door to multiple interpretations. The POSIX spec in 2024
reworded it, and it added a few examples to make it even clearer.

The input value of tm_isdst mandates if the break down calendar time is
interpreted in normal time or daylight summer time, but as said in a
different place the output values of the struct tm must be set as localtime
was called. The important point here is to notice that the localtime
call had to be done with the result time_t of the calculation done in
mktime.

This patch does not call localtime because all the work is already done in
mktime to determine the daylight state, and calling localtime is a bit
expensive as it has to call twice gmtime to determine the time.

Diffstat:
Minclude/scc/bits/darwin/amd64/arch/time.h | 2++
Minclude/scc/bits/dragonfly/amd64/arch/time.h | 2++
Minclude/scc/bits/freebsd/amd64/arch/time.h | 2++
Minclude/scc/bits/linux/amd64/arch/time.h | 2++
Minclude/scc/bits/linux/arm/arch/time.h | 2++
Minclude/scc/bits/linux/arm64/arch/time.h | 2++
Minclude/scc/bits/linux/i386/arch/time.h | 2++
Minclude/scc/bits/linux/ppc/arch/time.h | 2++
Minclude/scc/bits/netbsd/amd64/arch/time.h | 2++
Minclude/scc/bits/openbsd/amd64/arch/time.h | 2++
Msrc/libc/time/mktime.c | 51++++++++++++++++++++++++++++++---------------------
11 files changed, 50 insertions(+), 21 deletions(-)

diff --git a/include/scc/bits/darwin/amd64/arch/time.h b/include/scc/bits/darwin/amd64/arch/time.h @@ -1,5 +1,7 @@ #define _MAXYEAR 99999 #define _MINYEAR -99999 +#define _TIME_MAX LONG_MAX +#define _TIME_MIN LONG_MIN 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,5 +1,7 @@ #define _MAXYEAR 99999 #define _MINYEAR -99999 +#define _TIME_MAX LONG_MAX +#define _TIME_MIN LONG_MIN 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,5 +1,7 @@ #define _MAXYEAR 99999 #define _MINYEAR -99999 +#define _TIME_MAX LONG_MAX +#define _TIME_MIN LONG_MIN 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,5 +1,7 @@ #define _MAXYEAR 99999 #define _MINYEAR -99999 +#define _TIME_MAX LONG_MAX +#define _TIME_MIN LONG_MIN 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,5 +1,7 @@ #define _MAXYEAR 2037 #define _MINYEAR 1902 +#define _TIME_MAX LONG_MAX +#define _TIME_MIN LONG_MIN 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,5 +1,7 @@ #define _MAXYEAR 99999 #define _MINYEAR -99999 +#define _TIME_MAX LONG_MAX +#define _TIME_MIN LONG_MIN 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,5 +1,7 @@ #define _MAXYEAR 2037 #define _MINYEAR 1902 +#define _TIME_MAX LONG_MAX +#define _TIME_MIN LONG_MIN 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,5 +1,7 @@ #define _MAXYEAR 2037 #define _MINYEAR 1902 +#define _TIME_MAX LONG_MAX +#define _TIME_MIN LONG_MIN 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,5 +1,7 @@ #define _MAXYEAR 99999 #define _MINYEAR -99999 +#define _TIME_MAX LONG_MAX +#define _TIME_MIN LONG_MIN 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,5 +1,7 @@ #define _MAXYEAR 99999 #define _MINYEAR -99999 +#define _TIME_MAX LONG_MAX +#define _TIME_MIN LONG_MIN typedef long time_t; typedef long clock_t; diff --git a/src/libc/time/mktime.c b/src/libc/time/mktime.c @@ -99,19 +99,21 @@ normalize(struct tm *tm) } time_t -mktime(struct tm *tm) +mktime(struct tm *ptm) { time_t t; - int i, year; - struct tm *aux; + long off; + char *name; + int i, year, dst; + struct tm tm; - if (!normalize(tm)) + tm = *ptm; + if (!normalize(&tm)) return -1; t = 0; - year = tm->tm_year + BASEYEAR; - i = EPOCH; + year = tm.tm_year + BASEYEAR; if (year >= EPOCH) { while (i < year) t += _daysyear(i++) * SECDAY; @@ -120,27 +122,34 @@ mktime(struct tm *tm) t -= _daysyear(--i) * SECDAY; } - for (i = 0; i < tm->tm_mon; ++i) + for (i = 0; i < tm.tm_mon; ++i) t += _daysmon[i] * SECDAY; - t += tm->tm_sec; - t += tm->tm_min * SECMIN; - t += tm->tm_hour * SECHOUR; - t += (tm->tm_mday-1) * SECDAY; + t += tm.tm_sec; + t += tm.tm_min * SECMIN; + t += tm.tm_hour * SECHOUR; + t += (tm.tm_mday-1) * SECDAY; - aux = localtime(&t); + _tzset(); + dst = _daylight && _isdst(&tm); - if (tm->tm_isdst == -1) - tm->tm_isdst = aux->tm_isdst; + if (tm.tm_isdst == 0 || tm.tm_isdst < 0 && !dst) { + off = _timezone; + name = _tzname[0]; + } else { + off = _dstzone; + name = _tzname[1]; + } - if (tm->tm_isdst == 1) { - tm->tm_zone = _tzname[1]; - tm->tm_gmtoff = _dstzone; - } else { - tm->tm_zone = _tzname[0]; - tm->tm_gmtoff = _timezone; + if (off > 0 && t > _TIME_MAX - off + || off < 0 && t < _TIME_MIN + off) { + return -1; } - t += tm->tm_gmtoff; + t += off; + tm.tm_isdst = dst; + tm.tm_gmtoff = off; + tm.tm_zone = name; + *ptm = tm; return t; }