summaryrefslogtreecommitdiffstats
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
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
-rw-r--r--bin/date/date.125
-rw-r--r--bin/date/vary.c116
2 files changed, 76 insertions, 65 deletions
diff --git a/bin/date/date.1 b/bin/date/date.1
index 955505f..650a871 100644
--- a/bin/date/date.1
+++ b/bin/date/date.1
@@ -143,7 +143,9 @@ or backwards according to the remaining string, otherwise the relevant
part of the date is set. The date can be adjusted as many times as
required using these flags. Flags are processed in the order given.
.Pp
-Seconds are in the range 0-59, minutes are in the range 0-59, hours are
+When setting values
+.Pq rather than adjusting them ,
+seconds are in the range 0-59, minutes are in the range 0-59, hours are
in the range 1-12, month days are in the range 1-31, week days are in the
range 0-6
.Pq Sun-Sat ,
@@ -174,6 +176,27 @@ to the next
date that matches the given week day or month. This will not adjust the date
if the given week day or month is the same as the current one.
.Pp
+When a date is adjusted to a specific value or in units greater than hours,
+daylight savings time considerations are ignored.
+Adjustments in units of hours or less honour daylight savings time.
+So, assuming the current date is March 26, 0:30 and that the DST adjustment
+means that the clock goes forward at 01:00 to 02:00, using
+.Fl v No +1H
+will adjust the date to March 26, 2:30.
+Likewise, if the date is October 29, 0:30 and the DST adjustment means that
+the clock goes back at 02:00 to 01:00, using
+.Fl v No +3H
+will be necessary to reach October 20, 2:30.
+.Pp
+When the date is adjusted to a specific value that doesn't actually exist
+.Pq for example March 26, 1:30 BST 2000 ,
+the date will be silently adjusted forwards in units of one hour until it
+reaches a valid time.
+When the date is adjusted to a specific value that occurs twice
+.Pq for example October 29, 1:30 2000 ,
+the resulting timezone will be set so that the date matches the earlier of
+the two times.
+.Pp
Refer to the examples below for further details.
.El
.Pp
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