Add [-DWMY] flags for date adjustment.
Discussed with: freebsd-hackers
This commit is contained in:
parent
b0ed9cd762
commit
7ca215a690
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=27874
@ -1,8 +1,8 @@
|
||||
# @(#)Makefile 8.1 (Berkeley) 5/31/93
|
||||
# $Id$
|
||||
# $Id: Makefile,v 1.4 1997/02/22 14:02:30 peter Exp $
|
||||
|
||||
PROG= date
|
||||
SRCS= date.c netdate.c
|
||||
SRCS= date.c netdate.c vary.c
|
||||
DPADD= ${LIBUTIL}
|
||||
LDADD= -lutil
|
||||
|
||||
|
@ -33,7 +33,7 @@
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)date.1 8.3 (Berkeley) 4/28/95
|
||||
.\" $Id: date.1,v 1.11 1997/02/22 14:02:31 peter Exp $
|
||||
.\" $Id: date.1,v 1.12 1997/04/16 05:59:20 danny Exp $
|
||||
.\"
|
||||
.Dd November 17, 1993
|
||||
.Dt DATE 1
|
||||
@ -48,7 +48,8 @@
|
||||
.Op Fl t Ar minutes_west
|
||||
.Op Fl nu
|
||||
.Op Cm + Ns Ar format
|
||||
.Op [yy[mm[dd[hh]]]]mm[\&.ss]
|
||||
.Op Fl DWMY Ar [+|-]val
|
||||
.Op [[[[yy]mm]dd]hh]mm[\&.ss]
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
displays the current date and time when invoked without arguments.
|
||||
@ -97,6 +98,27 @@ by future calls to
|
||||
Display or set the date in
|
||||
.Tn UCT
|
||||
(universal) time.
|
||||
.It Fl DWMY
|
||||
Adjust the month day, week day, month or year according to
|
||||
.Ar val .
|
||||
If
|
||||
.Ar val
|
||||
is preceeded with a plus or minus sign, the date is adjusted forwards
|
||||
or backwards according to the remaining string, otherwise the relevent
|
||||
part of the date is set. The date can be adjusted as many times as
|
||||
required using these flags. Flags are processed in the order given.
|
||||
.Pp
|
||||
Month days are in the range 1-31, week days are in the range 0-6
|
||||
(sun-sat), months are in the range 1-12 (jan-dec) and years are in
|
||||
the range 80-38 or 1980-2038.
|
||||
.Pp
|
||||
The week day or month may be specified using a name rather than a
|
||||
number. If a name is used with the plus (or minus) sign, the date
|
||||
will be put forwards (or backwards) to the next (previous) date that
|
||||
matches the given week day or month. This will not adjust the date
|
||||
if the given week day or month is the same as the current one.
|
||||
.Pp
|
||||
Refer to the examples below for further details.
|
||||
.El
|
||||
.Pp
|
||||
An operand with a leading plus (``+'') sign signals a user-defined format
|
||||
@ -150,6 +172,40 @@ TIME: 13:36:16
|
||||
.Pp
|
||||
The command:
|
||||
.Bd -literal -offset indent
|
||||
date -M1 -Y+1
|
||||
.Ed
|
||||
.Pp
|
||||
will display:
|
||||
.Bd -literal -offset indent
|
||||
Sun Jan 4 03:15:24 GMT 1998
|
||||
.Ed
|
||||
.Pp
|
||||
(where it is currently Mon Aug 4 04:15:24 BST 1997).
|
||||
.Pp
|
||||
The command:
|
||||
.Bd -literal -offset indent
|
||||
date -D1 -M3 -Y0 -D-1
|
||||
.Ed
|
||||
.Pp
|
||||
will display the last day of February in the year 2000:
|
||||
.Bd -literal -offset indent
|
||||
Tue Feb 29 03:18:00 GMT 2000
|
||||
.Ed
|
||||
.Pp
|
||||
The command:
|
||||
.Bd -literal -offset indent
|
||||
date -D1 -M+1 -D-1 -W-fri
|
||||
.Ed
|
||||
.Pp
|
||||
will display the last friday of the month:
|
||||
.Bd -literal -offset indent
|
||||
Fri Aug 29 04:31:11 BST 1997
|
||||
.Ed
|
||||
.Pp
|
||||
(where it is currently Mon Aug 4 04:31:11 BST 1997).
|
||||
.Pp
|
||||
The command:
|
||||
.Bd -literal -offset indent
|
||||
date 8506131627
|
||||
.Ed
|
||||
.Pp
|
||||
|
@ -30,7 +30,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: date.c,v 1.12 1997/04/16 05:59:21 danny Exp $
|
||||
* $Id: date.c,v 1.13 1997/06/06 06:34:37 charnier Exp $
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
@ -57,6 +57,7 @@ static char const sccsid[] = "@(#)date.c 8.2 (Berkeley) 4/28/95";
|
||||
#include <locale.h>
|
||||
|
||||
#include "extern.h"
|
||||
#include "vary.h"
|
||||
|
||||
time_t tval;
|
||||
int retval, nflag;
|
||||
@ -79,12 +80,16 @@ main(argc, argv)
|
||||
char *format, buf[1024];
|
||||
char *endptr;
|
||||
int set_timezone;
|
||||
struct vary *v;
|
||||
const struct vary *badv;
|
||||
struct tm lt;
|
||||
|
||||
v = NULL;
|
||||
(void) setlocale(LC_TIME, "");
|
||||
tz.tz_dsttime = tz.tz_minuteswest = 0;
|
||||
rflag = 0;
|
||||
set_timezone = 0;
|
||||
while ((ch = getopt(argc, argv, "d:nr:ut:")) != -1)
|
||||
while ((ch = getopt(argc, argv, "D:W:M:Y:d:nr:ut:")) != -1)
|
||||
switch((char)ch) {
|
||||
case 'd': /* daylight savings time */
|
||||
tz.tz_dsttime = strtol(optarg, &endptr, 10) ? 1 : 0;
|
||||
@ -109,6 +114,12 @@ main(argc, argv)
|
||||
usage();
|
||||
set_timezone = 1;
|
||||
break;
|
||||
case 'D':
|
||||
case 'W':
|
||||
case 'M':
|
||||
case 'Y':
|
||||
v = vary_append(v, ch, optarg);
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
@ -141,7 +152,16 @@ main(argc, argv)
|
||||
if (*argv && **argv == '+')
|
||||
format = *argv + 1;
|
||||
|
||||
(void)strftime(buf, sizeof(buf), format, localtime(&tval));
|
||||
lt = *localtime(&tval);
|
||||
badv = vary_apply(v, <);
|
||||
if (badv) {
|
||||
fprintf(stderr, "-%c %s: Cannot apply date adjustment\n",
|
||||
badv->flag, badv->arg);
|
||||
vary_destroy(v);
|
||||
usage();
|
||||
}
|
||||
vary_destroy(v);
|
||||
(void)strftime(buf, sizeof(buf), format, <);
|
||||
(void)printf("%s\n", buf);
|
||||
exit(retval);
|
||||
}
|
||||
@ -239,6 +259,6 @@ usage()
|
||||
{
|
||||
(void)fprintf(stderr, "%s\n%s\n",
|
||||
"usage: date [-nu] [-d dst] [-r seconds] [-t west] [+format]",
|
||||
" [yy[mm[dd[hh]]]]mm[.ss]]");
|
||||
" [-DWMY [+|-]val] [[[[yy]mm]dd]HH]MM[.ss]]");
|
||||
exit(1);
|
||||
}
|
||||
|
337
bin/date/vary.c
Normal file
337
bin/date/vary.c
Normal file
@ -0,0 +1,337 @@
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "vary.h"
|
||||
|
||||
struct trans {
|
||||
int val;
|
||||
char *str;
|
||||
};
|
||||
|
||||
static struct trans trans_mon[] = {
|
||||
{ 1, "jan" }, { 2, "feb" }, { 3, "mar" }, { 4, "apr" }, { 5, "may" },
|
||||
{ 6, "jun" }, { 7, "jul" }, { 8, "aug" }, { 9, "sep" }, { 10, "oct" },
|
||||
{ 11, "nov" }, { 12, "dec" },
|
||||
{ 1, "january" }, { 2, "february" }, { 3, "march" }, { 4, "april" },
|
||||
{ 6, "june" }, { 7, "july" }, { 8, "august" }, { 9, "september" },
|
||||
{ 10, "october" }, { 11, "november" }, { 12, "december" },
|
||||
{ -1, NULL }
|
||||
};
|
||||
|
||||
static struct trans trans_wday[] = {
|
||||
{ 0, "sun" }, { 1, "mon" }, { 2, "tue" }, { 3, "wed" }, { 4, "thr" },
|
||||
{ 4, "thu" }, { 5, "fri" }, { 6, "sat" },
|
||||
{ 0, "sunday" }, { 1, "monday" }, { 2, "tuesday" }, { 3, "wednesday" },
|
||||
{ 4, "thursday" }, { 5, "friday" }, { 6, "saturday" },
|
||||
{ -1, NULL }
|
||||
};
|
||||
|
||||
static char digits[] = "0123456789";
|
||||
|
||||
static int
|
||||
trans(const struct trans t[], const char *arg)
|
||||
{
|
||||
int f;
|
||||
|
||||
if (strspn(arg, digits) == strlen(arg))
|
||||
return atoi(arg);
|
||||
|
||||
for (f = 0; t[f].val != -1; f++)
|
||||
if (!strcasecmp(t[f].str, arg))
|
||||
return t[f].val;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct vary *
|
||||
vary_append(struct vary *v, char flag, char *arg)
|
||||
{
|
||||
struct vary *result, **nextp;
|
||||
|
||||
if (!strchr("DWMY", flag))
|
||||
return 0;
|
||||
|
||||
if (v) {
|
||||
result = v;
|
||||
while (v->next)
|
||||
v = v->next;
|
||||
nextp = &v->next;
|
||||
} else
|
||||
nextp = &result;
|
||||
|
||||
*nextp = (struct vary *)malloc(sizeof(struct vary));
|
||||
(*nextp)->flag = flag;
|
||||
(*nextp)->arg = arg;
|
||||
(*nextp)->next = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
static int mdays[12] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
|
||||
static int
|
||||
daysinmonth(const struct tm *t)
|
||||
{
|
||||
int year;
|
||||
|
||||
year = t->tm_year + 1900;
|
||||
|
||||
if (t->tm_mon == 1)
|
||||
if (!(year % 400))
|
||||
return 29;
|
||||
else if (!(year % 100))
|
||||
return 28;
|
||||
else if (!(year % 4))
|
||||
return 29;
|
||||
else
|
||||
return 28;
|
||||
else if (t->tm_mon >= 0 && t->tm_mon < 12)
|
||||
return mdays[t->tm_mon];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
adjyear(struct tm *t, char type, int val)
|
||||
{
|
||||
switch (type) {
|
||||
case '+':
|
||||
t->tm_year += val;
|
||||
break;
|
||||
case '-':
|
||||
t->tm_year -= val;
|
||||
break;
|
||||
default:
|
||||
t->tm_year = val;
|
||||
if (t->tm_year < 69)
|
||||
t->tm_year += 100; /* as per date.c */
|
||||
else if (t->tm_year > 1900)
|
||||
t->tm_year -= 1900; /* struct tm holds years since 1900 */
|
||||
break;
|
||||
}
|
||||
return mktime(t) != -1;
|
||||
}
|
||||
|
||||
static int
|
||||
sadjyear(struct tm *t, char *arg)
|
||||
{
|
||||
switch (*arg) {
|
||||
case '+':
|
||||
case '-':
|
||||
return adjyear(t, *arg, atoi(arg+1));
|
||||
default:
|
||||
return adjyear(t, '\0', atoi(arg));
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
adjmon(struct tm *t, char type, int val, int istext)
|
||||
{
|
||||
if (val < 0)
|
||||
return 0;
|
||||
|
||||
switch (type) {
|
||||
case '+':
|
||||
if (istext)
|
||||
if (val <= t->tm_mon)
|
||||
val += 11 - t->tm_mon; /* early next year */
|
||||
else
|
||||
val -= t->tm_mon + 1; /* later this year */
|
||||
if (!adjyear(t, '+', (t->tm_mon + val) / 12))
|
||||
return 0;
|
||||
val %= 12;
|
||||
t->tm_mon += val;
|
||||
if (t->tm_mon > 11)
|
||||
t->tm_mon -= 12;
|
||||
break;
|
||||
|
||||
case '-':
|
||||
if (istext)
|
||||
if (val-1 > t->tm_mon)
|
||||
val = 13 - val + t->tm_mon; /* later last year */
|
||||
else
|
||||
val = t->tm_mon - val + 1; /* early this year */
|
||||
if (!adjyear(t, '-', val / 12))
|
||||
return 0;
|
||||
val %= 12;
|
||||
if (val > t->tm_mon) {
|
||||
if (!adjyear(t, '-', 1))
|
||||
return 0;
|
||||
val -= 12;
|
||||
}
|
||||
t->tm_mon -= val;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (val > 12 || val < 1)
|
||||
return 0;
|
||||
t->tm_mon = --val;
|
||||
}
|
||||
|
||||
return mktime(t) != -1;
|
||||
}
|
||||
|
||||
static int
|
||||
sadjmon(struct tm *t, char *arg)
|
||||
{
|
||||
int istext;
|
||||
int val;
|
||||
|
||||
switch (*arg) {
|
||||
case '+':
|
||||
case '-':
|
||||
istext = strspn(arg+1, digits) != strlen(arg+1);
|
||||
val = trans(trans_mon, arg+1);
|
||||
return adjmon(t, *arg, val, istext);
|
||||
default:
|
||||
istext = strspn(arg, digits) != strlen(arg);
|
||||
val = trans(trans_mon, arg);
|
||||
return adjmon(t, '\0', val, istext);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
adjday(struct tm *t, char type, int val)
|
||||
{
|
||||
int mdays;
|
||||
switch (type) {
|
||||
case '+':
|
||||
while (val) {
|
||||
mdays = daysinmonth(t);
|
||||
if (val > mdays - t->tm_mday) {
|
||||
val -= mdays - t->tm_mday + 1;
|
||||
t->tm_mday = 1;
|
||||
if (!adjmon(t, '+', 1, 0))
|
||||
return 0;
|
||||
} else {
|
||||
t->tm_mday += val;
|
||||
val = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '-':
|
||||
while (val)
|
||||
if (val >= t->tm_mday) {
|
||||
val -= t->tm_mday;
|
||||
t->tm_mday = 1;
|
||||
if (!adjmon(t, '-', 1, 0))
|
||||
return 0;
|
||||
t->tm_mday = daysinmonth(t);
|
||||
} else {
|
||||
t->tm_mday -= val;
|
||||
val = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (val > 0 && val <= daysinmonth(t))
|
||||
t->tm_mday = val;
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return mktime(t) != -1;
|
||||
}
|
||||
|
||||
static int
|
||||
sadjwday(struct tm *t, char *arg)
|
||||
{
|
||||
int istext;
|
||||
int val;
|
||||
|
||||
switch (*arg) {
|
||||
case '+':
|
||||
case '-':
|
||||
istext = strspn(arg+1, digits) != strlen(arg+1);
|
||||
val = trans(trans_wday, arg+1);
|
||||
break;
|
||||
default:
|
||||
istext = 0;
|
||||
val = trans(trans_wday, arg);
|
||||
break;
|
||||
}
|
||||
|
||||
if (val < 0)
|
||||
return 0;
|
||||
|
||||
switch (*arg) {
|
||||
case '+':
|
||||
if (istext)
|
||||
if (val < t->tm_wday)
|
||||
val = 7 - t->tm_wday + val; /* early next week */
|
||||
else
|
||||
val -= t->tm_wday; /* later this week */
|
||||
else
|
||||
val *= 7; /* "-W +5" == "5 weeks in the future" */
|
||||
return adjday(t, '+', val);
|
||||
case '-':
|
||||
if (istext)
|
||||
if (val > t->tm_wday)
|
||||
val = 7 - val + t->tm_wday; /* later last week */
|
||||
else
|
||||
val = t->tm_wday - val; /* early this week */
|
||||
else
|
||||
val *= 7; /* "-W -5" == "5 weeks ago" */
|
||||
return adjday(t, '-', val);
|
||||
default:
|
||||
if (val < t->tm_wday)
|
||||
return adjday(t, '-', t->tm_wday - val);
|
||||
else if (val > 6)
|
||||
return 0;
|
||||
else if (val > t->tm_wday)
|
||||
return adjday(t, '+', val - t->tm_wday);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
sadjday(struct tm *t, char *arg)
|
||||
{
|
||||
switch (*arg) {
|
||||
case '+':
|
||||
case '-':
|
||||
return adjday(t, *arg, atoi(arg+1));
|
||||
default:
|
||||
return adjday(t, '\0', atoi(arg));
|
||||
}
|
||||
}
|
||||
|
||||
const struct vary *
|
||||
vary_apply(const struct vary *v, struct tm *t)
|
||||
{
|
||||
for (; v; v = v->next) {
|
||||
switch (v->flag) {
|
||||
case 'D':
|
||||
if (!sadjday(t, v->arg))
|
||||
return v;
|
||||
break;
|
||||
case 'W':
|
||||
if (!sadjwday(t, v->arg))
|
||||
return v;
|
||||
break;
|
||||
case 'M':
|
||||
if (!sadjmon(t, v->arg))
|
||||
return v;
|
||||
break;
|
||||
case 'Y':
|
||||
if (!sadjyear(t, v->arg))
|
||||
return v;
|
||||
break;
|
||||
default:
|
||||
return v;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
vary_destroy(struct vary *v)
|
||||
{
|
||||
struct vary *n;
|
||||
|
||||
while (v) {
|
||||
n = v->next;
|
||||
free(v);
|
||||
v = n;
|
||||
}
|
||||
}
|
9
bin/date/vary.h
Normal file
9
bin/date/vary.h
Normal file
@ -0,0 +1,9 @@
|
||||
struct vary {
|
||||
char flag;
|
||||
char *arg;
|
||||
struct vary *next;
|
||||
};
|
||||
|
||||
extern struct vary *vary_append(struct vary *v, char flag, char *arg);
|
||||
extern const struct vary *vary_apply(const struct vary *v, struct tm *t);
|
||||
extern void vary_destroy(struct vary *v);
|
Loading…
Reference in New Issue
Block a user