Skip to content
4 changes: 2 additions & 2 deletions src/cmd/ksh93/tests/attributes.sh
Original file line number Diff line number Diff line change
Expand Up @@ -362,9 +362,9 @@ $SHELL -c 'builtin date' >/dev/null 2>&1 &&
# check env var changes against a builtin that uses the env var

SEC=1234252800
ETZ=EST5EDT
ETZ=EST5EDT,M3.2.0/2:00:00,M11.1.0/2:00:00
EDT=03
PTZ=PST8PDT
PTZ=PST8PDT,M3.2.0/2:00:00,M11.1.0/2:00:00
PDT=00

CMD="date -f%H \\#$SEC"
Expand Down
54 changes: 51 additions & 3 deletions src/cmd/ksh93/tests/printf.sh
Original file line number Diff line number Diff line change
Expand Up @@ -211,14 +211,62 @@ function do_test # 1:LINENO 2:printf-STRING 3:match-string
}

# The first tests require a time zone with one or more historical changes.
format='%Y-%m-%d %H:%M:%S'
export TZ=Europe/Riga

C='Historical changes (bad time)' # https://github.com/ksh93/ksh/issues/669
export TZ=Europe/Riga
format='%Y-%m-%d %H:%M:%S'
T '#236961303' '1977-07-05 17:35:03'
format='%s'
T '1977-07-05 17:35:03' '236961303'

export TZ=Europe/London
format='%Y-%m-%d %H:%M:%S'
T '#0' '1970-01-01 01:00:00'
format='%s'
T '1970-01-01 01:00:00' '0'

C='Before and after a historical change (bad time)'
export TZ=Pacific/Apia
format='%Y-%m-%d %H:%M:%S'
T '#1325239200' '2011-12-31 00:00:00'
T '#1325239199' '2011-12-29 23:59:59'
format='%s'
T '2011-12-31 00:00:00' '1325239200'
T '2011-12-29 23:59:59' '1325239199'

C='Historical change from one DST zone to another (bad time)'
export TZ=Europe/Chisinau
format='%Y-%m-%d %H:%M:%S'
T '#642286800' '1990-05-10 00:00:00'
format='%s'
T '1990-05-10 00:00:00' '642286800'

C='Historical change from DST to standard (bad time)'
export TZ=America/Indiana/Knox
format='%Y-%m-%d %H:%M:%S'
T '#688626000' '1991-10-28 00:00:00'
format='%s'
T '1991-10-28 00:00:00' '688626000'

C='Historical change from standard to DST (bad time)'
export TZ=America/Kentucky/Louisville
format='%Y-%m-%d %H:%M:%S'
T '#126766800' '1974-01-07 00:00:00'
format='%s'
T '1974-01-07 00:00:00' '126766800'

C='Historical change from standard to standard (bad time)'
export TZ=America/Argentina/San_Juan
format='%Y-%m-%d %H:%M:%S'
T '#1086148800' '2004-06-02 00:00:00'
format='%s'
T '2004-06-02 00:00:00' '1086148800'

C='POSIX timezone strings without rules (bad time, musl)' #https://github.com/ksh93/ksh/issues/976
export TZ=EST5EDT
format='%Y-%m-%d %H:%M:%S'
T '#1274252800' '2010-05-19 03:06:40'
format='%s'
T '2010-05-19 03:06:40' '1274252800'

format='%Y-%m-%d'
export TZ=UTC
Expand Down
21 changes: 17 additions & 4 deletions src/lib/libast/tm/tminit.c
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ tmlocal(time_t now)
char* e = NULL;
int i;
int m;
int o;
int p;
int isdst;
char* t;
struct tm* tp;
Expand Down Expand Up @@ -237,27 +239,38 @@ tmlocal(time_t now)

tm_info.zone = tm_info.local = &local;
n = tzwest(&now, &isdst);
p = n;
o = isdst;

/*
* compute local DST offset by roaming
* through the last 12 months until tzwest() changes
* with a system-recognized DST change
*/

for (i = 0; i < 12; i++)
{
now -= 31 * 24 * 60 * 60;
if ((m = tzwest(&now, &isdst)) != n)
if ((m = tzwest(&now, &isdst)) != n && ((!isdst && o) || (isdst && !o)))
{
m -= (n - p);
n = p;
if (!isdst)
{
isdst = n;
n = m;
m = isdst;
m = p;
}
m -= n;
break;
}
n = m;
if (i == 11)
{
n = p;
m = n;
}
}
m -= n;
isdst = o;
local.west = (short)n;
local.dst = (short)m;

Expand Down
22 changes: 22 additions & 0 deletions src/lib/libast/tm/tmxdate.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,11 @@ tmxdate(const char* s, char** e, Time_t now)
int dir;
int dst;
int zone;
int dst_old;
int west_old;
int isdst_old;
int first = 1;
int good_check = 0;
int c;
int f;
int i;
Expand Down Expand Up @@ -206,7 +211,13 @@ tmxdate(const char* s, char** e, Time_t now)
*/

tm = tmxtm(&ts, now, NULL, 1);
if (!first && dst_old == tm->tm_zone->dst && west_old == tm->tm_zone->west && isdst_old == tm->tm_isdst)
good_check = 1;
dst_old = tm->tm_zone->dst;
west_old = tm->tm_zone->west;
isdst_old = tm->tm_isdst;
tm_info.date = tm->tm_zone;
first = 0;
day = -1;
dir = 0;
dst = TM_DST;
Expand Down Expand Up @@ -1779,6 +1790,15 @@ tmxdate(const char* s, char** e, Time_t now)
tm->tm_mday += j;
}
}
tm = tmxtm(tm, tmxtime(tm, zone), tm->tm_zone, 1);
if (!first)
{
int offset = tm->tm_zone->west - west_old;
if (tm->tm_isdst)
offset += tm->tm_zone->dst - dst_old;
tm->tm_min += offset;
tmfix(tm);
}
now = tmxtime(tm, zone);
if (tm->tm_year <= 70 && tmxsec(now) > 31536000)
{
Expand All @@ -1787,5 +1807,7 @@ tmxdate(const char* s, char** e, Time_t now)
}
if (e)
*e = last;
if (!good_check)
goto reset;
return now;
}