Skip to content
Permalink
Browse files

date: add date/time setting capability

[Michael Forney: Moved functionality to setdate, other minor tweaks]
  • Loading branch information...
jvvv authored and michaelforney committed Jan 2, 2017
1 parent 9f718ec commit 4b13b23a689da5fc01c2a26affe8ad8087c777bf
Showing with 108 additions and 11 deletions.
  1. +47 −3 date.1
  2. +61 −8 date.c
50 date.1
@@ -3,20 +3,26 @@
.Os sbase
.Sh NAME
.Nm date
.Nd print date and time
.Nd print or set date and time
.Sh SYNOPSIS
.Nm
.Op Fl d Ar time
.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
.Nm
prints the date and time according to
.Xr locale 7
or
.Ar format
using
.Xr strftime 3 .
.Xr strftime 3
or sets the date.
.Sh OPTIONS
.Bl -tag -width Ds
.It Fl d Ar time
@@ -27,6 +33,44 @@ Unix epoch 1970-01-01T00:00:00Z.
.It Fl u
Print UTC time instead of local time.
.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
The
.Nm
69 date.c
@@ -1,14 +1,62 @@
/* See LICENSE file for copyright and license details. */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <time.h>

#include "util.h"

static 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);

ts.tv_sec = mktime(&date);
if (ts.tv_sec == (time_t)-1)
eprintf("mktime:");
ts.tv_nsec = 0;

if (clock_settime(CLOCK_REALTIME, &ts) == -1)
eprintf("clock_settime:");
}

int
@@ -19,8 +67,6 @@ main(int argc, char *argv[])
time_t t;
char buf[BUFSIZ], *fmt = "%c", *tz = "local";

t = time(NULL);

ARGBEGIN {
case 'd':
t = estrtonum(EARGF(usage()), 0, LLONG_MAX);
@@ -33,14 +79,21 @@ main(int argc, char *argv[])
usage();
} ARGEND

t = time(NULL);
if (t == (time_t)-1)
eprintf("time failed:");
if (!(now = tztime(&t)))
eprintf("%stime failed\n", tz);

if (argc) {
if (argc != 1 || argv[0][0] != '+')
if (argc != 1)
usage();
else
fmt = &argv[0][1];
if (argv[0][0] != '+') {
setdate(argv[0], now);
return 0;
}
fmt = &argv[0][1];
}
if (!(now = tztime(&t)))
eprintf("%stime failed\n", tz);

strftime(buf, sizeof(buf), fmt, now);
puts(buf);

0 comments on commit 4b13b23

Please sign in to comment.
You can’t perform that action at this time.