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}