summaryrefslogtreecommitdiffstats
path: root/bin/date/vary.c
diff options
context:
space:
mode:
authorbrian <brian@FreeBSD.org>2000-04-12 13:35:17 +0000
committerbrian <brian@FreeBSD.org>2000-04-12 13:35:17 +0000
commit0f8e1924fb0fd9657f280fe5dbdca99e0f9b5af5 (patch)
treedcfbc59962db287238611455a27a67cece2d555f /bin/date/vary.c
parent989ac2d698d83afd2733194fad8ca1cb98aaa61c (diff)
downloadFreeBSD-src-0f8e1924fb0fd9657f280fe5dbdca99e0f9b5af5.zip
FreeBSD-src-0f8e1924fb0fd9657f280fe5dbdca99e0f9b5af5.tar.gz
Change -v so that variences in units of days or less are sensitive to
DST. Explain in more detail what date -v does when mixed with DST. Previous code suggested broken by: wollman
Diffstat (limited to 'bin/date/vary.c')
-rw-r--r--bin/date/vary.c116
1 files changed, 52 insertions, 64 deletions
diff --git a/bin/date/vary.c b/bin/date/vary.c
index 9063d38..4e46d1b2 100644
--- a/bin/date/vary.c
+++ b/bin/date/vary.c
@@ -53,25 +53,16 @@ static struct trans trans_wday[] = {
};
static char digits[] = "0123456789";
-static int adjhour(struct tm *, char, int);
+static int adjhour(struct tm *, char, int, 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);
+ time_t ret;
+
+ while ((ret = mktime(t)) == -1 && t->tm_year > 68 && t->tm_year < 138)
+ /* While mktime() fails, adjust by an hour */
+ adjhour(t, type == '-' ? type : '+', 1, 0);
return ret;
}
@@ -134,7 +125,7 @@ daysinmonth(const struct tm *t)
static int
-adjyear(struct tm *t, char type, int val)
+adjyear(struct tm *t, char type, int val, int mk)
{
switch (type) {
case '+':
@@ -151,11 +142,11 @@ adjyear(struct tm *t, char type, int val)
t->tm_year -= 1900; /* struct tm holds years since 1900 */
break;
}
- return domktime(t, type) != -1;
+ return !mk || domktime(t, type) != -1;
}
static int
-adjmon(struct tm *t, char type, int val, int istext)
+adjmon(struct tm *t, char type, int val, int istext, int mk)
{
if (val < 0)
return 0;
@@ -169,7 +160,7 @@ adjmon(struct tm *t, char type, int val, int istext)
val -= t->tm_mon + 1; /* later this year */
}
if (val) {
- if (!adjyear(t, '+', (t->tm_mon + val) / 12))
+ if (!adjyear(t, '+', (t->tm_mon + val) / 12, 0))
return 0;
val %= 12;
t->tm_mon += val;
@@ -186,11 +177,11 @@ adjmon(struct tm *t, char type, int val, int istext)
val = t->tm_mon - val + 1; /* early this year */
}
if (val) {
- if (!adjyear(t, '-', val / 12))
+ if (!adjyear(t, '-', val / 12, 0))
return 0;
val %= 12;
if (val > t->tm_mon) {
- if (!adjyear(t, '-', 1))
+ if (!adjyear(t, '-', 1, 0))
return 0;
val -= 12;
}
@@ -204,11 +195,11 @@ adjmon(struct tm *t, char type, int val, int istext)
t->tm_mon = --val;
}
- return domktime(t, type) != -1;
+ return !mk || domktime(t, type) != -1;
}
static int
-adjday(struct tm *t, char type, int val)
+adjday(struct tm *t, char type, int val, int mk)
{
int mdays;
@@ -219,7 +210,7 @@ adjday(struct tm *t, char type, int val)
if (val > mdays - t->tm_mday) {
val -= mdays - t->tm_mday + 1;
t->tm_mday = 1;
- if (!adjmon(t, '+', 1, 0))
+ if (!adjmon(t, '+', 1, 0, 0))
return 0;
} else {
t->tm_mday += val;
@@ -232,7 +223,7 @@ adjday(struct tm *t, char type, int val)
if (val >= t->tm_mday) {
val -= t->tm_mday;
t->tm_mday = 1;
- if (!adjmon(t, '-', 1, 0))
+ if (!adjmon(t, '-', 1, 0, 0))
return 0;
t->tm_mday = daysinmonth(t);
} else {
@@ -248,11 +239,11 @@ adjday(struct tm *t, char type, int val)
break;
}
- return domktime(t, type) != -1;
+ return !mk || domktime(t, type) != -1;
}
static int
-adjwday(struct tm *t, char type, int val, int istext)
+adjwday(struct tm *t, char type, int val, int istext, int mk)
{
if (val < 0)
return 0;
@@ -266,7 +257,7 @@ adjwday(struct tm *t, char type, int val, int istext)
val -= t->tm_wday; /* later this week */
else
val *= 7; /* "-v+5w" == "5 weeks in the future" */
- return !val || adjday(t, '+', val);
+ return !val || adjday(t, '+', val, 0);
case '-':
if (istext) {
if (val > t->tm_wday)
@@ -275,31 +266,21 @@ adjwday(struct tm *t, char type, int val, int istext)
val = t->tm_wday - val; /* early this week */
} else
val *= 7; /* "-v-5w" == "5 weeks ago" */
- return !val || adjday(t, '-', val);
+ return !val || adjday(t, '-', val, 0);
default:
if (val < t->tm_wday)
- return adjday(t, '-', t->tm_wday - val);
+ return adjday(t, '-', t->tm_wday - val, 0);
else if (val > 6)
return 0;
else if (val > t->tm_wday)
- return adjday(t, '+', val - t->tm_wday);
+ return adjday(t, '+', val - t->tm_wday, 0);
}
return 1;
}
static int
-adjhour(struct tm *t, char type, int val)
+adjhour(struct tm *t, char type, int val, int mk)
{
- /*
- * 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;
@@ -312,7 +293,7 @@ adjhour(struct tm *t, char type, int val)
val %= 24;
t->tm_hour += val;
t->tm_hour %= 24;
- if (!adjday(t, '+', days))
+ if (!adjday(t, '+', days, 0))
return 0;
}
break;
@@ -328,7 +309,7 @@ adjhour(struct tm *t, char type, int val)
val -= 24;
}
t->tm_hour -= val;
- if (!adjday(t, '-', val / 24))
+ if (!adjday(t, '-', days, 0))
return 0;
}
break;
@@ -339,11 +320,11 @@ adjhour(struct tm *t, char type, int val)
t->tm_hour = val;
}
- return domktime(t, type) != -1;
+ return !mk || domktime(t, type) != -1;
}
static int
-adjmin(struct tm *t, char type, int val)
+adjmin(struct tm *t, char type, int val, int mk)
{
if (val < 0)
return 0;
@@ -351,7 +332,7 @@ adjmin(struct tm *t, char type, int val)
switch (type) {
case '+':
if (val) {
- if (!adjhour(t, '+', (t->tm_min + val) / 60))
+ if (!adjhour(t, '+', (t->tm_min + val) / 60, 0))
return 0;
val %= 60;
t->tm_min += val;
@@ -362,11 +343,11 @@ adjmin(struct tm *t, char type, int val)
case '-':
if (val) {
- if (!adjhour(t, '-', val / 60))
+ if (!adjhour(t, '-', val / 60, 0))
return 0;
val %= 60;
if (val > t->tm_min) {
- if (!adjhour(t, '-', 1))
+ if (!adjhour(t, '-', 1, 0))
return 0;
val -= 60;
}
@@ -380,11 +361,11 @@ adjmin(struct tm *t, char type, int val)
t->tm_min = val;
}
- return domktime(t, type) != -1;
+ return !mk || domktime(t, type) != -1;
}
static int
-adjsec(struct tm *t, char type, int val)
+adjsec(struct tm *t, char type, int val, int mk)
{
if (val < 0)
return 0;
@@ -392,7 +373,7 @@ adjsec(struct tm *t, char type, int val)
switch (type) {
case '+':
if (val) {
- if (!adjmin(t, '+', (t->tm_sec + val) / 60))
+ if (!adjmin(t, '+', (t->tm_sec + val) / 60, 0))
return 0;
val %= 60;
t->tm_sec += val;
@@ -403,11 +384,11 @@ adjsec(struct tm *t, char type, int val)
case '-':
if (val) {
- if (!adjmin(t, '-', val / 60))
+ if (!adjmin(t, '-', val / 60, 0))
return 0;
val %= 60;
if (val > t->tm_sec) {
- if (!adjmin(t, '-', 1))
+ if (!adjmin(t, '-', 1, 0))
return 0;
val -= 60;
}
@@ -421,7 +402,7 @@ adjsec(struct tm *t, char type, int val)
t->tm_sec = val;
}
- return domktime(t, type) != -1;
+ return !mk || domktime(t, type) != -1;
}
const struct vary *
@@ -444,15 +425,18 @@ vary_apply(const struct vary *v, struct tm *t)
if (len < 2)
return v;
+ if (type == '\0')
+ t->tm_isdst = -1;
+
if (strspn(arg, digits) != len-1) {
val = trans(trans_wday, arg);
if (val != -1) {
- if (!adjwday(t, type, val, 1))
+ if (!adjwday(t, type, val, 1, 1))
return v;
} else {
val = trans(trans_mon, arg);
if (val != -1) {
- if (!adjmon(t, type, val, 1))
+ if (!adjmon(t, type, val, 1, 1))
return v;
} else
return v;
@@ -463,31 +447,35 @@ vary_apply(const struct vary *v, struct tm *t)
switch (which) {
case 'S':
- if (!adjsec(t, type, val))
+ if (!adjsec(t, type, val, 1))
return v;
break;
case 'M':
- if (!adjmin(t, type, val))
+ if (!adjmin(t, type, val, 1))
return v;
break;
case 'H':
- if (!adjhour(t, type, val))
+ if (!adjhour(t, type, val, 1))
return v;
break;
case 'd':
- if (!adjday(t, type, val))
+ t->tm_isdst = -1;
+ if (!adjday(t, type, val, 1))
return v;
break;
case 'w':
- if (!adjwday(t, type, val, 0))
+ t->tm_isdst = -1;
+ if (!adjwday(t, type, val, 0, 1))
return v;
break;
case 'm':
- if (!adjmon(t, type, val, 0))
+ t->tm_isdst = -1;
+ if (!adjmon(t, type, val, 0, 1))
return v;
break;
case 'y':
- if (!adjyear(t, type, val))
+ t->tm_isdst = -1;
+ if (!adjyear(t, type, val, 1))
return v;
break;
default:
OpenPOWER on IntegriCloud