Re: [hackers] [sbase][Patch] date: add date/time setting capability

From: John Vogel <jvogel4_AT_stny.rr.com>
Date: Sun, 1 Jan 2017 20:09:53 -0500

On Sun, 1 Jan 2017 13:43:59 -0800
Michael Forney <mforney_AT_mforney.org> wrote:

> On 12/29/16, John Vogel <jvogel4_AT_stny.rr.com> wrote:
> > On Thu, 29 Dec 2016 12:11:33 +0100
> > Hiltjo Posthuma <hiltjo_AT_codemadness.org> wrote:
> >
> >> Nitpicks:
> >> - Check if digit in date_field().
> >> - Style: don't declare variables in the inner scope, just use the
> >> function scope for struct tm date; and struct timespec ts;
> >>
> >> Kind regards,
> >> Hiltjo
> >>
> >
> > Thanks for your input.
>
> Hmm, I think your fix for this made the patch a bit awkward. I suggest
> keeping the original structure, but changing date_field to eprintf
> when it hits a non-digit, so you don't have to deal with all that
> error checking in main.
>

Good point. Thank you.

-- >8 --
 date.1 | 46 +++++++++++++++++++++++++++++++++++++++++++--
 date.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 104 insertions(+), 9 deletions(-)

diff --git a/date.1 b/date.1
index 29081a5..0171936 100644
--- a/date.1
+++ b/date.1
_AT_@ -3,12 +3,15 @@
 .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
+.Sm off
+.Op Ar mmddHHMM Oo Oo Ar CC Oc Ar yy Oc
+.Sm on
 .Sh DESCRIPTION
 .Nm
 prints the date and time according to
_AT_@ -16,7 +19,8 @@ prints the date and time according to
 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
_AT_@ -27,6 +31,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 a value for setting the systems 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
diff --git a/date.c b/date.c
index 1671e1f..92ef9f4 100644
--- a/date.c
+++ b/date.c
_AT_@ -1,14 +1,27 @@
 /* See LICENSE file for copyright and license details. */
 #include <stdio.h>
 #include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <errno.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
+date_field(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');
 }
 
 int
_AT_@ -16,11 +29,11 @@ main(int argc, char *argv[])
 {
         struct tm *now;
         struct tm *(*tztime)(const time_t *) = localtime;
+ struct tm date;
+ struct timespec ts;
         time_t t;
         char buf[BUFSIZ], *fmt = "%c", *tz = "local";
 
- t = time(NULL);
-
         ARGBEGIN {
         case 'd':
                 t = estrtonum(EARGF(usage()), 0, LLONG_MAX);
_AT_@ -33,14 +46,54 @@ 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
+ } else if (argv[0][0] == '+') {
                         fmt = &argv[0][1];
+ } else {
+ switch (strlen(argv[0])) {
+ case 8:
+ date.tm_year = now->tm_year;
+ break;
+ case 10:
+ date.tm_year = date_field(argv[0], 8);
+ if (date.tm_year < 69)
+ date.tm_year += 100;
+ break;
+ case 12:
+ date.tm_year = ((date_field(argv[0], 8) - 19) * 100) + date_field(argv[0], 10);
+ break;
+ default:
+ eprintf("invalid date format: %s\n", argv[0]);
+ break;
+ }
+
+ date.tm_mon = date_field(argv[0], 0) - 1;
+ date.tm_mday = date_field(argv[0], 2);
+ date.tm_hour = date_field(argv[0], 4);
+ date.tm_min = date_field(argv[0], 6);
+
+ t = mktime(&date);
+ if (t == (time_t)-1)
+ eprintf("mktime failed: bad calender date/time: %s\n", argv[0]);
+
+ ts.tv_sec = t;
+ ts.tv_nsec = 0;
+
+ if (clock_settime(CLOCK_REALTIME, &ts) == -1)
+ eprintf("clock_settime failed:");
+
+ return 0;
+ }
         }
- if (!(now = tztime(&t)))
- eprintf("%stime failed\n", tz);
 
         strftime(buf, sizeof(buf), fmt, now);
         puts(buf);
Received on Mon Jan 02 2017 - 02:09:53 CET

This archive was generated by hypermail 2.3.0 : Mon Jan 02 2017 - 02:12:43 CET