From owner-freebsd-bugs Sun Jan 9 4:50:10 2000 Delivered-To: freebsd-bugs@freebsd.org Received: from freefall.freebsd.org (freefall.FreeBSD.ORG [204.216.27.21]) by hub.freebsd.org (Postfix) with ESMTP id ABE3115243 for ; Sun, 9 Jan 2000 04:50:01 -0800 (PST) (envelope-from gnats@FreeBSD.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.9.3/8.9.2) id EAA32383; Sun, 9 Jan 2000 04:50:01 -0800 (PST) (envelope-from gnats@FreeBSD.org) Received: from cichlids.com (as10-063.rp-plus.de [149.221.96.63]) by hub.freebsd.org (Postfix) with ESMTP id 33B6314C1B for ; Sun, 9 Jan 2000 04:47:10 -0800 (PST) (envelope-from alex@cichlids.com) Received: from cichlids.cichlids.com (cichlids.cichlids.com [192.168.0.10]) by cichlids.com (Postfix) with ESMTP id C9524AB92 for ; Sun, 9 Jan 2000 13:47:18 +0100 (CET) Received: (from root@localhost) by cichlids.cichlids.com (8.9.3/8.9.3) id NAA03218; Sun, 9 Jan 2000 13:47:08 +0100 (CET) (envelope-from alex) Message-Id: <200001091247.NAA03218@cichlids.cichlids.com> Date: Sun, 9 Jan 2000 13:47:08 +0100 (CET) From: Alexander Langer Reply-To: alex@cichlids.com To: FreeBSD-gnats-submit@freebsd.org X-Send-Pr-Version: 3.2 Subject: bin/16005: add new option to date(1) Sender: owner-freebsd-bugs@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.org >Number: 16005 >Category: bin >Synopsis: add new option to date(1) >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Sun Jan 9 04:50:01 PST 2000 >Closed-Date: >Last-Modified: >Originator: Alexander Langer >Release: FreeBSD 4.0-CURRENT i386 >Organization: nope >Environment: -current >Description: 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. >Fix: diff -ru date.old/date.1 date/date.1 --- date.old/date.1 Wed Nov 10 14:34:38 1999 +++ date/date.1 Sun Jan 9 13:36:45 2000 @@ -48,6 +48,7 @@ .Op Fl r Ar seconds .Op Fl t Ar minutes_west .Op Fl v Ns Ar [+|-]val Ns Op ymwdHMS +.Op Fl V Ns Ar [+|-]val Ns Op ymwdHMS .Ar ... .Op Fl f Ar fmt Ar date | [[[[[cc]yy]mm]dd]HH]MM[\&.ss] .Op Cm + Ns Ar format @@ -148,6 +149,16 @@ if the given week day or month is the same as the current one. .Pp Refer to the examples below for further details. +.It Fl V +Adjust the second, minute, hour, month day, week day, month or year according to +.Ar val , +but behave logically. +.Pp +I.e., if you are at Dec 31th and adjust the date with +.Fl -V-1m +the date will be Nov 30th. +.Fl v +would have produced a date of Dec 1st. .El .Pp An operand with a leading plus (``+'') sign signals a user-defined format diff -ru date.old/date.c date/date.c --- date.old/date.c Wed Dec 29 17:50:08 1999 +++ date/date.c Sun Jan 9 12:41:54 2000 @@ -97,7 +97,7 @@ rflag = 0; jflag = nflag = 0; set_timezone = 0; - while ((ch = getopt(argc, argv, "d:f:jnr:t:uv:")) != -1) + while ((ch = getopt(argc, argv, "d:f:jnr:t:uv:V:")) != -1) switch((char)ch) { case 'd': /* daylight savings time */ tz.tz_dsttime = strtol(optarg, &endptr, 10) ? 1 : 0; @@ -128,8 +128,11 @@ case 'u': /* do everything in GMT */ (void)setenv("TZ", "GMT0", 1); break; + case 'V': + v = vary_append(v, optarg, 1); + break; case 'v': - v = vary_append(v, optarg); + v = vary_append(v, optarg, 0); break; default: usage(); diff -ru date.old/vary.c date/vary.c --- date.old/vary.c Sat Aug 28 01:13:59 1999 +++ date/vary.c Sun Jan 9 13:39:53 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; @@ -167,9 +169,16 @@ if (val > t->tm_mon) { if (!adjyear(t, '-', 1)) return 0; - val -= 12; } - t->tm_mon -= val; + if (vary_logical) { + for (; val > 0; val--) { + t->tm_mday -= ((mdays[t->tm_mon] == 0) ? 28 + is_leap(t->tm_year + 1900) : mdays[t->tm_mon]) - ((mdays[(t->tm_mon == 0) ? 13 : t->tm_mon - 1] == 0) ? 28 + is_leap(t->tm_year + 1900) : mdays[t->tm_mon + (t->tm_mon == 0) ? 11 : -1]); + t->tm_mon -= 1; + } + } else + t->tm_mon -= val; + if (t->tm_mon < 0) + t->tm_mon += 12; break; default: @@ -192,7 +200,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 +213,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 +387,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 +409,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 +440,8 @@ return v; break; case 'm': - if (!adjmon(t, type, val, 0)) - return v; + if (!adjmon(t, type, val, 0, vary_logical)) + return v; break; case 'y': if (!adjyear(t, type, val)) diff -ru date.old/vary.h date/vary.h --- date.old/vary.h Sat Aug 28 01:14:00 1999 +++ date/vary.h Sun Jan 9 12:42:09 2000 @@ -29,8 +29,9 @@ struct vary { char *arg; struct vary *next; + char vary_logical; }; -extern struct vary *vary_append(struct vary *v, char *arg); +extern struct vary *vary_append(struct vary *v, char *arg, char vary_logical); extern const struct vary *vary_apply(const struct vary *v, struct tm *t); extern void vary_destroy(struct vary *v); >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message