master xplshn/aruu / cmd / posix / date.c
  1/* See LICENSE file for copyright and license details. */
  2
  3
  4#include <ctype.h>
  5#include <stdio.h>
  6#include <stdlib.h>
  7#include <string.h>
  8#include <time.h>
  9
 10#include "util.h"
 11
 12static void
 13usage(void)
 14{
 15	eprintf("usage: %s [-u] [-d time] [+format | mmddHHMM[[CC]yy]]\n", argv0);
 16}
 17
 18static int
 19datefield(const char *s, size_t i)
 20{
 21	if (!isdigit(s[i]) || !isdigit(s[i+1]))
 22		eprintf("invalid date format: %s\n", s);
 23
 24	return (s[i] - '0') * 10 + (s[i+1] - '0');
 25}
 26
 27static void
 28setdate(const char *s, struct tm *now)
 29{
 30	struct tm date;
 31	struct timespec ts;
 32
 33	switch (strlen(s)) {
 34	case 8:
 35		date.tm_year = now->tm_year;
 36		break;
 37	case 10:
 38		date.tm_year = datefield(s, 8);
 39		if (date.tm_year < 69)
 40			date.tm_year += 100;
 41		break;
 42	case 12:
 43		date.tm_year = ((datefield(s, 8) - 19) * 100) + datefield(s, 10);
 44		break;
 45	default:
 46		eprintf("invalid date format: %s\n", s);
 47		break;
 48	}
 49
 50	date.tm_mon = datefield(s, 0) - 1;
 51	date.tm_mday = datefield(s, 2);
 52	date.tm_hour = datefield(s, 4);
 53	date.tm_min = datefield(s, 6);
 54	date.tm_sec = 0;
 55	date.tm_isdst = -1;
 56
 57	ts.tv_sec = mktime(&date);
 58	if (ts.tv_sec == -1)
 59		eprintf("mktime:");
 60	ts.tv_nsec = 0;
 61
 62	if (clock_settime(CLOCK_REALTIME, &ts) == -1)
 63		eprintf("clock_settime:");
 64}
 65
 66// ?man date: print or set system date and time
 67// ?man arguments: +format | mmddHHMM[[CC]yy
 68// ?man display or configure the system date and time
 69int
 70main(int argc, char *argv[])
 71{
 72	struct tm *now;
 73	time_t t;
 74	char buf[BUFSIZ], *fmt = "%a %b %e %H:%M:%S %Z %Y";
 75
 76	t = time(NULL);
 77	if (t == -1)
 78		eprintf("time:");
 79
 80	ARGBEGIN {
 81	// ?man -d:num: specify directory
 82	case 'd':
 83		t = estrtonum(EARGF(usage()), 0, LLONG_MAX);
 84		break;
 85	// ?man -u: unbuffered output
 86	case 'u':
 87		if (setenv("TZ", "UTC0", 1) < 0)
 88			eprintf("setenv:");
 89		break;
 90	default:
 91		usage();
 92	} ARGEND
 93
 94	if (!(now = localtime(&t)))
 95		eprintf("localtime:");
 96	if (argc) {
 97		if (argc != 1)
 98			usage();
 99		if (argv[0][0] != '+') {
100			setdate(argv[0], now);
101			return 0;
102		}
103		fmt = &argv[0][1];
104	}
105
106	strftime(buf, sizeof(buf), fmt, now);
107	puts(buf);
108
109	return fshut(stdout, "<stdout>");
110}