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