scc

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

commit b491da26d599c2a3a21ec0e5eae5ecbd1da1f5cf
parent 0a7b2d884f05ae91341e8d2361917819dee51de3
Author: Roberto E. Vargas Caballero <k0ga@shike2.net>
Date:   Fri, 17 Apr 2026 17:31:38 +0200

libc/time: Simplify the time arch interface

The interface was using too many global variables, and it exposed some
of the details of the dst rules in the posix spec, and these details
can be hidden in the arch part, that enables some very simple implementation
in the cases where would be needed.

This commit also fixes many bugs found in the process.

Diffstat:
Msrc/libc/arch/posix/_tzone.c | 67++++++++++++++++++++++++++++++++++++++++++++++---------------------
Msrc/libc/time/localtime.c | 30+++++++++++-------------------
Msrc/libc/time/mktime.c | 10+++++-----
3 files changed, 62 insertions(+), 45 deletions(-)

diff --git a/src/libc/arch/posix/_tzone.c b/src/libc/arch/posix/_tzone.c @@ -17,13 +17,15 @@ enum { JULIAN, }; +int _daylight; +char *_tzname[2]; +long _timezone, _dstzone; + static char st[TOKENSIZ], ds[TOKENSIZ], tokstr[TOKENSIZ]; static int tok; -char *_tzname[2]; -time_t _tzstdoff, _tzdstoff; -time_t _tzstart, _tzend; -int _tzjulian; +static int start, end; +static int julian; static int next(char *str) @@ -147,7 +149,7 @@ offset(void) static int std(void) { - time_t off; + long off; if (tok != STR) return 0; @@ -156,7 +158,7 @@ std(void) if ((off = offset()) == -1) return 0; - _tzstdoff = off; + _timezone = off; return 1; } @@ -164,7 +166,7 @@ std(void) static int dst(void) { - time_t off; + long off; if (tok != STR) return 0; @@ -172,11 +174,11 @@ dst(void) next(NULL); if ((off = offset()) == -1) - _tzdstoff = off; + _dstzone = _timezone + SECHOUR; else - _tzdstoff = _tzstdoff + SECHOUR; + _dstzone = off; - return 1; + return _daylight = 1; } static int @@ -198,7 +200,7 @@ yday(void) next(NULL); if (n == 0) return -1; - _tzjulian = 1; + julian = 1; break; case GREGORIAN: n = num(365); @@ -216,23 +218,30 @@ rule(void) return 0; if (!accept(',')) return 0; - if ((_tzstart = yday()) == -1) + if ((start = yday()) == -1) return 0; if (!accept(',')) return 0; - if ((_tzend = yday()) == -1) + if ((end = yday()) == -1) return 0; } void _tzset(void) { - char *tz = getenv("TZ"); + static char *tz; + char *s = getenv("TZ"); + + if (s && tz && strcmp(s, tz) == 0) + return; + tz = s; + _daylight = 0; _tzname[1] = _tzname[0] = "UTC"; - _tzstdoff = _tzdstoff = (time_t) -1; - _tzstart = _tzend = (time_t) -1; - _tzjulian = 0; + _timezone = _dstzone = -1; + + start = end = -1; + julian = 0; if (!tz) goto adjust; @@ -246,8 +255,24 @@ _tzset(void) goto adjust; adjust: - if (_tzstdoff == -1) - _tzstdoff = _gmtoff(_tzname[0]); - if (_tzdstoff == -1) - _tzdstoff = _gmtoff(_tzname[1]); + if (!_daylight) + _tzname[1] = _tzname[0]; + if (_timezone == -1) + _timezone = _gmtoff(_tzname[0]); + if (_dstzone == -1) + _dstzone = _gmtoff(_tzname[1]); +} + +int +_isdst(struct tm *tm) +{ + int yday; + + yday = tm->tm_yday; + + if (julian && yday+1 < 60 || FEBDAYS(tm->tm_year) < 29) + yday++; + if (yday >= start && yday <= end && tm->tm_hour >= 2) + return 1; + return 0; } diff --git a/src/libc/time/localtime.c b/src/libc/time/localtime.c @@ -7,36 +7,28 @@ struct tm * localtime(const time_t *timep) { + time_t t; + int dst; + long off; char *name; struct tm *tm; - time_t t, off; - int yday, dst; - static int first = 1; t = *timep; tm = gmtime(&t); - yday = tm->tm_yday; + _tzset(); - if (first) - _tzset(); - first = 0; - - off = _tzstdoff; - name = _tzname[0]; - dst = 0; - - if (_tzjulian && yday+1 < 60 || FEBDAYS(tm->tm_year) < 29) - yday++; - - if (yday >= _tzstart && yday <= _tzend && tm->tm_hour >= 2) { - off = _tzdstoff; - name = _tzname[1]; + if (_daylight && _isdst(tm)) { dst = 1; + off = _dstzone; + name = _tzname[1]; + } else { + dst = 0; + off = _timezone; + name = _tzname[0]; } t += off; tm = gmtime(&t); - tm->tm_zone = name; tm->tm_isdst = dst; tm->tm_gmtoff = off; diff --git a/src/libc/time/mktime.c b/src/libc/time/mktime.c @@ -108,8 +108,8 @@ mktime(struct tm *tm) if (!normalize(tm)) return -1; + t = 0; year = tm->tm_year + BASEYEAR; - for (i = EPOCH; i < year; ++i) t += _daysyear(i) * SECDAY; for (i = 0; i < tm->tm_mon; ++i) @@ -125,11 +125,11 @@ mktime(struct tm *tm) tm->tm_isdst = aux->tm_isdst; if (tm->tm_isdst == 1) { - tm->tm_zone =_tzname[1]; - tm->tm_gmtoff = _tzstdoff; + tm->tm_zone = _tzname[1]; + tm->tm_gmtoff = _dstzone; } else { - tm->tm_zone =_tzname[0]; - tm->tm_gmtoff = _tzdstoff; + tm->tm_zone = _tzname[0]; + tm->tm_gmtoff = _timezone; } t += tm->tm_gmtoff;