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:
parent
bd18f33408
commit
a625bfec63
181
bin/date/vary.c
181
bin/date/vary.c
@ -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 *
|
||||
|
Loading…
x
Reference in New Issue
Block a user