1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59#define FOR_date
60#include "toys.h"
61
62GLOBALS(
63 char *s, *r, *I, *D, *d;
64
65 unsigned nano;
66)
67
68
69static void parse_date(char *str, time_t *t)
70{
71 char *new_tz = NULL, *old_tz, *s = str;
72
73 if (!strncmp(str, "TZ=\"", 4)) {
74
75 new_tz = str+4;
76 if (!(str = strchr(new_tz, '"'))) xvali_date(0, s);
77 *str++ = 0;
78 while (isspace(*str)) str++;
79
80
81 old_tz = getenv("TZ");
82 setenv("TZ", new_tz, 1);
83 tzset();
84 }
85 time(t);
86 xparsedate(str, t, &TT.nano, 1);
87 if (new_tz) {
88 if (old_tz) setenv("TZ", old_tz, 1);
89 else unsetenv("TZ");
90 }
91}
92
93
94static void puts_time(char *fmt, struct tm *tm)
95{
96 char *s, *snap, *out;
97
98 for (s = fmt;;s++) {
99 long n = 0;
100
101
102 if (*(snap = s)) {
103 if (*s != '%') continue;
104 if (*++s == 'N') n = 9;
105 else if (isdigit(*s) && s[1] == 'N') n = *s++-'0';
106 else if (*s == ':' && s[1] == 'z') s++, n++;
107 else continue;
108 }
109
110
111 if (*s) *snap = 0;
112
113 out = toybuf;
114 if (*fmt) {
115 if (!strftime(out, sizeof(toybuf)-12, fmt, tm))
116 perror_exit("bad format '%s'", fmt);
117 out += strlen(out);
118 }
119
120 if (*s == 'N') {
121 sprintf(out, "%09u", TT.nano);
122 out[n] = 0;
123 } else if (*s == 'z') {
124 strftime(out, 10, "%z", tm);
125 memmove(out+4, out+3, strlen(out+3)+1);
126 out[3] = ':';
127 }
128 xputsn(toybuf);
129 if (!*s || !*(fmt = s+1)) break;
130 }
131 xputc('\n');
132}
133
134void date_main(void)
135{
136 char *setdate = *toys.optargs, *format_string = "%a %b %e %H:%M:%S %Z %Y",
137 *tz = NULL;
138 time_t t;
139
140 if (FLAG(I)) {
141 char *iso_formats[] = {"%F","%FT%H%:z","%FT%R%:z","%FT%T%:z","%FT%T,%N%:z"};
142 int i = stridx("dhmsn", (TT.I && *TT.I) ? *TT.I : 'd');
143
144 if (i<0) help_exit("bad -I: %s", TT.I);
145 format_string = xstrdup(iso_formats[i]);
146 }
147
148 if (FLAG(u)) {
149 tz = getenv("TZ");
150 setenv("TZ", "UTC", 1);
151 tzset();
152 }
153
154 if (TT.d) {
155 if (TT.D) {
156 struct tm tm = {};
157 char *s = strptime(TT.d, TT.D+(*TT.D=='+'), &tm);
158
159 t = (s && *s) ? xvali_date(&tm, s) : xvali_date(0, TT.d);
160 } else parse_date(TT.d, &t);
161 } else {
162 struct timespec ts;
163 struct stat st;
164
165 if (TT.r) {
166 xstat(TT.r, &st);
167 ts = st.st_mtim;
168 } else clock_gettime(CLOCK_REALTIME, &ts);
169
170 t = ts.tv_sec;
171 TT.nano = ts.tv_nsec;
172 }
173
174 if (FLAG(s)) {
175 if (setdate) help_exit("can't set two dates at once");
176 setdate = TT.s;
177 }
178
179
180 if (!setdate);
181
182 else if (*setdate == '+') {
183 format_string = toys.optargs[0]+1;
184 setdate = toys.optargs[1];
185
186
187 } else if (setdate) {
188 struct timeval tv;
189
190 parse_date(setdate, &t);
191 tv.tv_sec = t;
192 tv.tv_usec = TT.nano/1000;
193 if (settimeofday(&tv, NULL) < 0) perror_msg("cannot set date");
194 }
195
196 puts_time(format_string, localtime(&t));
197
198 if (FLAG(u)) {
199 if (tz) setenv("TZ", tz, 1);
200 else unsetenv("TZ");
201 tzset();
202 }
203 if (CFG_TOYBOX_FREE && FLAG(I)) free(format_string);
204}
205