This PR should become assigned to brian@FreeBSD.org. As discussed via Email, this new optione (-V) does logical date adjustment. That means, if it is Dec. 31th -V-1m would procude Nov. 30th (1 month earlier), and not Dec 1st. That's useful for scripts, e.g. when you want something like date -V-1m +%m to print out the LAST month. On Dec. 31th -v prints out the CURRENT month. How-To-Repeat: date -v-1m on a month with 31 days and the foregoing month has less days.
> >Number: 16005 > >Category: bin > >Synopsis: add new option to date(1) It doesn't seem to work as advertised. $ date -V99y -V12m -V31d -V12H -V0M -V0S -V-1m Wed Dec 1 12:00:00 GMT 1999 -- Brian <brian@Awfulhak.org> <brian@FreeBSD.org> <http://www.Awfulhak.org> <brian@OpenBSD.org> Don't _EVER_ lose your sense of humour ! <brian@FreeBSD.org.uk>
Responsible Changed From-To: freebsd-bugs->brian Apparently, Mr Somers asked for this one.
Thus spake Brian Somers (brian@Awfulhak.org): > It doesn't seem to work as advertised. > $ date -V99y -V12m -V31d -V12H -V0M -V0S -V-1m > Wed Dec 1 12:00:00 GMT 1999 dumb. Maybe I mixed some patches... it worked for me, but now it doesn't do, too. Strange. Well, I retook a look and found a MUCH easier solution to the problem ;-) Try this to vary.c, the other stuff doesn't change. --- ../date.old/vary.c Sat Aug 28 01:13:59 1999 +++ vary.c Wed Jan 12 16:07:00 2000 @@ -68,7 +68,7 @@ } struct vary * -vary_append(struct vary *v, char *arg) +vary_append(struct vary *v, char *arg, char vary_logical) { struct vary *result, **nextp; @@ -82,6 +82,7 @@ *nextp = (struct vary *)malloc(sizeof(struct vary)); (*nextp)->arg = arg; + (*nextp)->vary_logical = vary_logical; (*nextp)->next = NULL; return result; } @@ -132,8 +133,9 @@ return mktime(t) != -1; } +#define is_leap(year) (!((year) % 4) && (! ((year) % 400) || (year) % 100)) static int -adjmon(struct tm *t, char type, int val, int istext) +adjmon(struct tm *t, char type, int val, int istext, char vary_logical) { if (val < 0) return 0; @@ -170,6 +172,8 @@ val -= 12; } t->tm_mon -= val; + if (vary_logical && t->tm_mday > (mdays[t->tm_mon] == 0) ? 28 + is_leap(t->tm_year + 1900) : mdays[t->tm_mon]) + t->tm_mday = (mdays[t->tm_mon] == 0) ? 28 + is_leap(t->tm_year + 1900) : mdays[t->tm_mon]; break; default: @@ -192,7 +196,7 @@ 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; @@ -205,7 +209,7 @@ 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 { @@ -379,10 +383,12 @@ char *arg; int len; int val; + char vary_logical; for (; v; v = v->next) { type = *v->arg; arg = v->arg; + vary_logical = v->vary_logical; if (type == '+' || type == '-') arg++; else @@ -399,7 +405,7 @@ } else { val = trans(trans_mon, arg); if (val != -1) { - if (!adjmon(t, type, val, 1)) + if (!adjmon(t, type, val, 1, vary_logical)) return v; } else return v; @@ -430,8 +436,8 @@ return v; break; case 'm': - if (!adjmon(t, type, val, 0)) + if (!adjmon(t, type, val, 0, vary_logical)) return v; break; case 'y': if (!adjyear(t, type, val)) Hope this works now. I think it does. $ /usr/obj/usr/src/bin/date/date -V99y -V12m -V31d -V-46m -lutil Do 29 Feb 1996 16:08:05 CET $ /usr/obj/usr/src/bin/date/date -V99y -V12m -V31d -V-1m Di 30 Nov 1999 16:08:25 CET Alex
Responsible Changed From-To: brian->alex Alex can have this - he submitted it. I'm not sure (retrospectively) that I agree that we need this. As things are, -v behaves in line with mktime (normalising a struct time). The -V thing can always be done with ``date -v1d -v-1m +%m'' etc.
State Changed From-To: open->closed No need for this.