diff options
author | brian <brian@FreeBSD.org> | 2000-04-12 13:35:17 +0000 |
---|---|---|
committer | brian <brian@FreeBSD.org> | 2000-04-12 13:35:17 +0000 |
commit | 0f8e1924fb0fd9657f280fe5dbdca99e0f9b5af5 (patch) | |
tree | dcfbc59962db287238611455a27a67cece2d555f /bin/date/vary.c | |
parent | 989ac2d698d83afd2733194fad8ca1cb98aaa61c (diff) | |
download | FreeBSD-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.c | 116 |
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: |