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:
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;