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

From: John Vogel <jvogel4_AT_stny.rr.com>
Date: Thu, 5 May 2016 15:20:35 -0400

From 79079cdc560d68257c110482c730ab043c7f4c0f Mon Sep 17 00:00:00 2001
From: John Vogel <jvogel4_AT_stny.rr.com>
Date: Thu, 5 May 2016 15:01:36 -0400
Subject: [sbase][Patch] date: add date/time setting capability
To: hackers_AT_suckless.org

Signed-off-by: John Vogel <jvogel4_AT_stny.rr.com>
---
 date.1 | 46 ++++++++++++++++++++++++++++++++++++++++++++--
 date.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 102 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..f3db89f 100644
--- a/date.c
+++ b/date.c
_AT_@ -1,6 +1,8 @@
 /* See LICENSE file for copyright and license details. */
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
+#include <errno.h>
 #include <time.h>
 
 #include "util.h"
_AT_@ -8,19 +10,20 @@
 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);
 }
 
 int
 main(int argc, char *argv[])
 {
 	struct tm *now;
+	struct tm date;
 	struct tm *(*tztime)(const time_t *) = localtime;
+	struct timespec ts;
 	time_t t;
+	size_t i, j, len;
 	char buf[BUFSIZ], *fmt = "%c", *tz = "local";
 
-	t = time(NULL);
-
 	ARGBEGIN {
 	case 'd':
 		t = estrtonum(EARGF(usage()), 0, LLONG_MAX);
_AT_@ -33,14 +36,62 @@ main(int argc, char *argv[])
 		usage();
 	} ARGEND
 
+	t = time(NULL);
+
+	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 {
+			len = strlen(argv[0]);
+
+			switch (len) {
+			case 8:
+				fmt = "%m %d %H %M";
+				break;
+			case 10:
+				fmt = "%m %d %H %M %y";
+				break;
+			case 12:
+				fmt = "%m %d %H %M %C %y";
+				break;
+			default:
+				eprintf("invalid date format: %s\n", argv[0]);
+			}
+
+			/* strptime does not handle the mmddHHMM[[CC]yy] format with
+			 * the leading zeroes for each specifier unless they are separated.
+			 */
+			for (i = 0, j = 0; i < len; i++) {
+				buf[j++] = argv[0][i];
+				if (i && i < len-1 && (i%2))
+					buf[j++] = ' ';
+			}
+			buf[j] = '\0';
+
+			if (strptime(buf, fmt, &date) == NULL)
+				eprintf("strptime failed: invalid input: %s\n", argv[0]);
+
+			if (len == 8)
+				date.tm_year = now->tm_year;
+
+			t = mktime(&date);
+			if (t == (time_t)-1)
+				eprintf("mktime failed: bad calendar 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: %s\n", strerror(errno));
+
+			return fshut(stdout, "<stdout>");
+		}
 	}
-	if (!(now = tztime(&t)))
-		eprintf("%stime failed\n", tz);
 
 	strftime(buf, sizeof(buf), fmt, now);
 	puts(buf);
-- 
2.7.4
Received on Thu May 05 2016 - 21:20:35 CEST

This archive was generated by hypermail 2.3.0 : Thu May 05 2016 - 21:24:14 CEST