Skip site navigation (1)Skip section navigation (2)
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>