summaryrefslogtreecommitdiffstats
path: root/bin
diff options
context:
space:
mode:
authorbrian <brian@FreeBSD.org>2000-04-05 01:59:36 +0000
committerbrian <brian@FreeBSD.org>2000-04-05 01:59:36 +0000
commit85b9c1f90b38b35ecf1d4c4e9a22bf122c2cef1c (patch)
tree30d5a56f301878bd9c061838c0bf405cddbbe665 /bin
parenta00d5b661c9af018104cb3aab9f227dce8bbccee (diff)
downloadFreeBSD-src-85b9c1f90b38b35ecf1d4c4e9a22bf122c2cef1c.zip
FreeBSD-src-85b9c1f90b38b35ecf1d4c4e9a22bf122c2cef1c.tar.gz
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
Diffstat (limited to 'bin')
-rw-r--r--bin/date/vary.c181
1 files changed, 117 insertions, 64 deletions
diff --git a/bin/date/vary.c b/bin/date/vary.c
index 97556fd..9063d38 100644
--- a/bin/date/vary.c
+++ b/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 *
OpenPOWER on IntegriCloud