Always give mktime a timeval with tm_isdst set to -1, otherwise

things get a bit out-of-phase when we step backwards 1 hour from
between 0:00 and 1:00 on the first of the month following the
transition into Summer time.  This is probably actually a bug
in mktime().

PR:	10963

If mktime() fails and 68 < year < 138, assume that the reason is
because of Summer time and adjust up or down according to our
adjusting context by one hour.  This assumes that all DSTs are
multiples of 1 hour.

PR:	6223, 17750
This commit is contained in:
Brian Somers 2000-04-05 01:59:36 +00:00
parent bd18f33408
commit a625bfec63
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=59022

View File

@ -53,6 +53,28 @@ static struct trans trans_wday[] = {
};
static char digits[] = "0123456789";
static int adjhour(struct tm *, char, int);
static int
domktime(struct tm *t, char type)
{
int ret;
/*
* Don't let mktime have a specific tm_isdst value. If we do,
* it gets confused when we ``vary'' in and out of Summer time
*/
t->tm_isdst = -1;
if ((ret = mktime(t)) == -1 && t->tm_year > 68 && t->tm_year < 138)
/*
* If mktime() fails, adjust by an hour. If we're actually
* bridging a savings of several hours, we'll recurse several
* times.
*/
ret = adjhour(t, type == '-' ? type : '+', 1);
return ret;
}
static int
trans(const struct trans t[], const char *arg)
@ -129,7 +151,7 @@ adjyear(struct tm *t, char type, int val)
t->tm_year -= 1900; /* struct tm holds years since 1900 */
break;
}
return mktime(t) != -1;
return domktime(t, type) != -1;
}
static int
@ -146,12 +168,14 @@ adjmon(struct tm *t, char type, int val, int istext)
else
val -= t->tm_mon + 1; /* later this year */
}
if (!adjyear(t, '+', (t->tm_mon + val) / 12))
return 0;
val %= 12;
t->tm_mon += val;
if (t->tm_mon > 11)
t->tm_mon -= 12;
if (val) {
if (!adjyear(t, '+', (t->tm_mon + val) / 12))
return 0;
val %= 12;
t->tm_mon += val;
if (t->tm_mon > 11)
t->tm_mon -= 12;
}
break;
case '-':
@ -161,15 +185,17 @@ adjmon(struct tm *t, char type, int val, int istext)
else
val = t->tm_mon - val + 1; /* early this year */
}
if (!adjyear(t, '-', val / 12))
return 0;
val %= 12;
if (val > t->tm_mon) {
if (!adjyear(t, '-', 1))
if (val) {
if (!adjyear(t, '-', val / 12))
return 0;
val -= 12;
val %= 12;
if (val > t->tm_mon) {
if (!adjyear(t, '-', 1))
return 0;
val -= 12;
}
t->tm_mon -= val;
}
t->tm_mon -= val;
break;
default:
@ -178,13 +204,14 @@ adjmon(struct tm *t, char type, int val, int istext)
t->tm_mon = --val;
}
return mktime(t) != -1;
return domktime(t, type) != -1;
}
static int
adjday(struct tm *t, char type, int val)
{
int mdays;
switch (type) {
case '+':
while (val) {
@ -221,7 +248,7 @@ adjday(struct tm *t, char type, int val)
break;
}
return mktime(t) != -1;
return domktime(t, type) != -1;
}
static int
@ -238,17 +265,17 @@ adjwday(struct tm *t, char type, int val, int istext)
else
val -= t->tm_wday; /* later this week */
else
val *= 7; /* "-W +5" == "5 weeks in the future" */
return adjday(t, '+', val);
val *= 7; /* "-v+5w" == "5 weeks in the future" */
return !val || adjday(t, '+', val);
case '-':
if (istext)
if (istext) {
if (val > t->tm_wday)
val = 7 - val + t->tm_wday; /* later last week */
else
val = t->tm_wday - val; /* early this week */
else
val *= 7; /* "-W -5" == "5 weeks ago" */
return adjday(t, '-', val);
} else
val *= 7; /* "-v-5w" == "5 weeks ago" */
return !val || adjday(t, '-', val);
default:
if (val < t->tm_wday)
return adjday(t, '-', t->tm_wday - val);
@ -263,29 +290,47 @@ adjwday(struct tm *t, char type, int val, int istext)
static int
adjhour(struct tm *t, char type, int val)
{
/*
* We've got to be careful here in case
* domktime() calls
* adjhour() calls
* adjday() calls
* domktime() calls
* adjhour() and recurses forever. It's vital that we've adjusted our
* number of hours before calling adjday().
*/
if (val < 0)
return 0;
switch (type) {
case '+':
if (!adjday(t, '+', (t->tm_hour + val) / 24))
return 0;
val %= 24;
t->tm_hour += val;
if (t->tm_hour > 23)
t->tm_hour -= 24;
if (val) {
int days;
days = (t->tm_hour + val) / 24;
val %= 24;
t->tm_hour += val;
t->tm_hour %= 24;
if (!adjday(t, '+', days))
return 0;
}
break;
case '-':
if (!adjday(t, '-', val / 24))
return 0;
val %= 24;
if (val > t->tm_hour) {
if (!adjday(t, '-', 1))
if (val) {
int days;
days = val / 24;
val %= 24;
if (val > t->tm_hour) {
days++;
val -= 24;
}
t->tm_hour -= val;
if (!adjday(t, '-', val / 24))
return 0;
val -= 24;
}
t->tm_hour -= val;
break;
default:
@ -294,7 +339,7 @@ adjhour(struct tm *t, char type, int val)
t->tm_hour = val;
}
return mktime(t) != -1;
return domktime(t, type) != -1;
}
static int
@ -305,24 +350,28 @@ adjmin(struct tm *t, char type, int val)
switch (type) {
case '+':
if (!adjhour(t, '+', (t->tm_min + val) / 60))
return 0;
val %= 60;
t->tm_min += val;
if (t->tm_min > 59)
t->tm_min -= 60;
if (val) {
if (!adjhour(t, '+', (t->tm_min + val) / 60))
return 0;
val %= 60;
t->tm_min += val;
if (t->tm_min > 59)
t->tm_min -= 60;
}
break;
case '-':
if (!adjhour(t, '-', val / 60))
return 0;
val %= 60;
if (val > t->tm_min) {
if (!adjhour(t, '-', 1))
if (val) {
if (!adjhour(t, '-', val / 60))
return 0;
val -= 60;
val %= 60;
if (val > t->tm_min) {
if (!adjhour(t, '-', 1))
return 0;
val -= 60;
}
t->tm_min -= val;
}
t->tm_min -= val;
break;
default:
@ -331,7 +380,7 @@ adjmin(struct tm *t, char type, int val)
t->tm_min = val;
}
return mktime(t) != -1;
return domktime(t, type) != -1;
}
static int
@ -342,24 +391,28 @@ adjsec(struct tm *t, char type, int val)
switch (type) {
case '+':
if (!adjmin(t, '+', (t->tm_sec + val) / 60))
return 0;
val %= 60;
t->tm_sec += val;
if (t->tm_sec > 59)
t->tm_sec -= 60;
if (val) {
if (!adjmin(t, '+', (t->tm_sec + val) / 60))
return 0;
val %= 60;
t->tm_sec += val;
if (t->tm_sec > 59)
t->tm_sec -= 60;
}
break;
case '-':
if (!adjmin(t, '-', val / 60))
return 0;
val %= 60;
if (val > t->tm_sec) {
if (!adjmin(t, '-', 1))
if (val) {
if (!adjmin(t, '-', val / 60))
return 0;
val -= 60;
val %= 60;
if (val > t->tm_sec) {
if (!adjmin(t, '-', 1))
return 0;
val -= 60;
}
t->tm_sec -= val;
}
t->tm_sec -= val;
break;
default:
@ -368,7 +421,7 @@ adjsec(struct tm *t, char type, int val)
t->tm_sec = val;
}
return mktime(t) != -1;
return domktime(t, type) != -1;
}
const struct vary *