Date: Sun, 9 Jan 2000 13:47:08 +0100 (CET) From: Alexander Langer <alex@cichlids.com> To: FreeBSD-gnats-submit@freebsd.org Subject: bin/16005: add new option to date(1) Message-ID: <200001091247.NAA03218@cichlids.cichlids.com>
next in thread | raw e-mail | index | archive | help
>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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200001091247.NAA03218>
