Change the behaviour of `-v' so that, e.g., stepping a month back
on March 31 won't take you to March 2 or 3 (now the result will be the last day of February.) In general, now stepping by months from the last days of the current month A will take you to the very last day of the target month B if B is shorter than A. The previous version would just step to March 31 and rely on mktime(3) to correct the date. Despite its simplicity, such way was counter-intuitive to users and caused pain to shell script writers. Noticed by: Igor Timkin <ivt at gamma dot ru> Approved by: brian MFC after: 2 weeks
This commit is contained in:
parent
8f0d968bd8
commit
d3e240cb45
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=133381
@ -31,7 +31,7 @@
|
||||
.\" @(#)date.1 8.3 (Berkeley) 4/28/95
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd November 17, 1993
|
||||
.Dd August 9, 2004
|
||||
.Dt DATE 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -218,6 +218,22 @@ When the date is adjusted to a specific value that occurs twice
|
||||
the resulting timezone will be set so that the date matches the earlier of
|
||||
the two times.
|
||||
.Pp
|
||||
Adjusting the date by months is inherently ambiguous because
|
||||
a month is a unit of variable length depending on the current date.
|
||||
This kind of date adjustment is applied in the most intuitive way.
|
||||
First of all,
|
||||
.Nm
|
||||
tries to preserve the day of the month.
|
||||
If it is impossible because the target month is shorter than the present one,
|
||||
the last day of the target month will be the result.
|
||||
For example, using
|
||||
.Fl v No +1m
|
||||
on May 31 will adjust the date to June 30, while using the same option
|
||||
on January 30 will result in the date adjusted to the last day of February.
|
||||
This approach is also believed to make the most sense for shell scripting.
|
||||
Nevertheless, be aware that going forth and back by the same number of
|
||||
months may take you to a different date.
|
||||
.Pp
|
||||
Refer to the examples below for further details.
|
||||
.El
|
||||
.Pp
|
||||
@ -295,6 +311,12 @@ will display the last day of February in the year 2000:
|
||||
.Pp
|
||||
.Dl "Tue Feb 29 03:18:00 GMT 2000"
|
||||
.Pp
|
||||
So will do the command:
|
||||
.Pp
|
||||
.Dl "date -v30d -v3m -v0y -v-1m"
|
||||
.Pp
|
||||
because there is no such date as the 30th of February.
|
||||
.Pp
|
||||
The command:
|
||||
.Pp
|
||||
.Dl "date -v1d -v+1m -v-1d -v-fri"
|
||||
|
@ -148,6 +148,8 @@ adjyear(struct tm *t, char type, int val, int mk)
|
||||
static int
|
||||
adjmon(struct tm *t, char type, int val, int istext, int mk)
|
||||
{
|
||||
int lmdays;
|
||||
|
||||
if (val < 0)
|
||||
return 0;
|
||||
|
||||
@ -195,6 +197,11 @@ adjmon(struct tm *t, char type, int val, int istext, int mk)
|
||||
t->tm_mon = --val;
|
||||
}
|
||||
|
||||
/* e.g., -v-1m on March, 31 is the last day of February in common sense */
|
||||
lmdays = daysinmonth(t);
|
||||
if (t->tm_mday > lmdays)
|
||||
t->tm_mday = lmdays;
|
||||
|
||||
return !mk || domktime(t, type) != -1;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user