date: add date/time setting capability

[Michael Forney: Moved functionality to setdate, other minor tweaks]
This commit is contained in:
John Vogel 2017-01-01 20:09:53 -05:00 committed by Michael Forney
parent 1b41610a82
commit ed78aef5b1
2 changed files with 110 additions and 11 deletions

52
date.1
View File

@ -3,12 +3,17 @@
.Os sbase .Os sbase
.Sh NAME .Sh NAME
.Nm date .Nm date
.Nd print date and time .Nd print or set date and time
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm .Nm
.Op Fl d Ar time .Op Fl d Ar time
.Op Fl u .Op Fl u
.Op Cm + Ns Ar format .Oo
.Cm + Ns Ar format |
.Sm off
.Ar mmddHHMM Oo Oo Ar CC Oc Ar yy Oc
.Sm on
.Oc
.Sh DESCRIPTION .Sh DESCRIPTION
.Nm .Nm
prints the date and time according to prints the date and time according to
@ -16,7 +21,8 @@ prints the date and time according to
or or
.Ar format .Ar format
using using
.Xr strftime 3 . .Xr strftime 3
or sets the date.
.Sh OPTIONS .Sh OPTIONS
.Bl -tag -width Ds .Bl -tag -width Ds
.It Fl d Ar time .It Fl d Ar time
@ -25,8 +31,46 @@ Print
given as the number of seconds since the given as the number of seconds since the
Unix epoch 1970-01-01T00:00:00Z. Unix epoch 1970-01-01T00:00:00Z.
.It Fl u .It Fl u
Print UTC time instead of local time. Print or set UTC time instead of local time.
.El .El
.Pp
An operand with a leading plus
.Pq Cm +
sign signals a user-defined format string using
.Xr strftime 3
conversion specifications.
.Pp
An operand without a leading plus sign is interpreted as a value
for setting the system's current date and time. The canonical
representation for setting the date and time is:
.Pp
.Bl -tag -width Ds -compact -offset indent
.It Ar mm
The month of the year, from 01 to 12.
.It Ar dd
The day of the month, from 01 to 31.
.It Ar HH
The hour of the day, from 00 to 23.
.It Ar MM
The minute of the hour, from 00 to 59.
.It Ar CC
The first two digits of the year (the century).
.It Ar yy
The second two digits of the year.
If
.Ar yy
is specified, but
.Ar CC
is not, a value for
.Ar yy
between 69 and 99 results in a
.Ar CC
value of 19. Otherwise, a
.Ar CC
value of 20 is used.
.El
.Pp
The century and year are optional. The default is the current year.
.Sh STANDARDS .Sh STANDARDS
The The
.Nm .Nm

69
date.c
View File

@ -1,6 +1,8 @@
/* See LICENSE file for copyright and license details. */ /* See LICENSE file for copyright and license details. */
#include <ctype.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <time.h> #include <time.h>
#include "util.h" #include "util.h"
@ -8,7 +10,55 @@
static void static void
usage(void) usage(void)
{ {
eprintf("usage: %s [-u] [-d time] [+format]\n", argv0); eprintf("usage: %s [-u] [-d time] [+format | mmddHHMM[[CC]yy]]\n", argv0);
}
static int
datefield(const char *s, size_t i)
{
if (!isdigit(s[i]) || !isdigit(s[i+1]))
eprintf("invalid date format: %s\n", s);
return (s[i] - '0') * 10 + (s[i+1] - '0');
}
static void
setdate(const char *s, struct tm *now)
{
struct tm date;
struct timespec ts;
switch (strlen(s)) {
case 8:
date.tm_year = now->tm_year;
break;
case 10:
date.tm_year = datefield(s, 8);
if (date.tm_year < 69)
date.tm_year += 100;
break;
case 12:
date.tm_year = ((datefield(s, 8) - 19) * 100) + datefield(s, 10);
break;
default:
eprintf("invalid date format: %s\n", s);
break;
}
date.tm_mon = datefield(s, 0) - 1;
date.tm_mday = datefield(s, 2);
date.tm_hour = datefield(s, 4);
date.tm_min = datefield(s, 6);
date.tm_sec = 0;
date.tm_isdst = -1;
ts.tv_sec = mktime(&date);
if (ts.tv_sec == -1)
eprintf("mktime:");
ts.tv_nsec = 0;
if (clock_settime(CLOCK_REALTIME, &ts) == -1)
eprintf("clock_settime:");
} }
int int
@ -19,6 +69,8 @@ main(int argc, char *argv[])
char buf[BUFSIZ], *fmt = "%c"; char buf[BUFSIZ], *fmt = "%c";
t = time(NULL); t = time(NULL);
if (t == -1)
eprintf("time:");
ARGBEGIN { ARGBEGIN {
case 'd': case 'd':
@ -32,14 +84,17 @@ main(int argc, char *argv[])
usage(); usage();
} ARGEND } ARGEND
if (argc) {
if (argc != 1 || argv[0][0] != '+')
usage();
else
fmt = &argv[0][1];
}
if (!(now = localtime(&t))) if (!(now = localtime(&t)))
eprintf("localtime:"); eprintf("localtime:");
if (argc) {
if (argc != 1)
usage();
if (argv[0][0] != '+') {
setdate(argv[0], now);
return 0;
}
fmt = &argv[0][1];
}
strftime(buf, sizeof(buf), fmt, now); strftime(buf, sizeof(buf), fmt, now);
puts(buf); puts(buf);