Bug 16005 - add new option to date(1)
Summary: add new option to date(1)
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: bin (show other bugs)
Version: 4.0-CURRENT
Hardware: Any Any
: Normal Affects Only Me
Assignee: alex
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2000-01-09 12:50 UTC by Alexander Langer
Modified: 2001-05-08 12:08 UTC (History)
0 users

See Also:


Attachments
file.diff (4.71 KB, patch)
2000-01-09 12:50 UTC, Alexander Langer
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Alexander Langer 2000-01-09 12:50:01 UTC
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.
Comment 1 Brian Somers 2000-01-11 11:46:49 UTC
> >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>
Comment 2 Sheldon Hearn freebsd_committer freebsd_triage 2000-01-11 13:48:36 UTC
Responsible Changed
From-To: freebsd-bugs->brian

Apparently, Mr Somers asked for this one. 

Comment 3 alex 2000-01-12 15:09:01 UTC
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
Comment 4 Brian Somers freebsd_committer freebsd_triage 2001-02-05 00:42:17 UTC
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.
Comment 5 alex freebsd_committer freebsd_triage 2001-05-08 12:07:34 UTC
State Changed
From-To: open->closed

No need for this.