51 |
* and does not support -Ins |
* and does not support -Ins |
52 |
* -D FMT is a bbox extension for _input_ conversion of -d DATE |
* -D FMT is a bbox extension for _input_ conversion of -d DATE |
53 |
*/ |
*/ |
54 |
|
|
55 |
|
//kbuild:lib-$(CONFIG_DATE) += date.o |
56 |
|
|
57 |
|
//config:config DATE |
58 |
|
//config: bool "date" |
59 |
|
//config: default y |
60 |
|
//config: help |
61 |
|
//config: date is used to set the system date or display the |
62 |
|
//config: current time in the given format. |
63 |
|
//config: |
64 |
|
//config:config FEATURE_DATE_ISOFMT |
65 |
|
//config: bool "Enable ISO date format output (-I)" |
66 |
|
//config: default y |
67 |
|
//config: depends on DATE |
68 |
|
//config: help |
69 |
|
//config: Enable option (-I) to output an ISO-8601 compliant |
70 |
|
//config: date/time string. |
71 |
|
//config: |
72 |
|
//config:config FEATURE_DATE_NANO |
73 |
|
//config: bool "Support %[num]N nanosecond format specifier" |
74 |
|
//config: default n |
75 |
|
//config: depends on DATE |
76 |
|
//config: help |
77 |
|
//config: Support %[num]N format specifier. Adds ~250 bytes of code. |
78 |
|
//config: |
79 |
|
//config:config FEATURE_DATE_COMPAT |
80 |
|
//config: bool "Support weird 'date MMDDhhmm[[YY]YY][.ss]' format" |
81 |
|
//config: default y |
82 |
|
//config: depends on DATE |
83 |
|
//config: help |
84 |
|
//config: System time can be set by 'date -s DATE' and simply 'date DATE', |
85 |
|
//config: but formats of DATE string are different. 'date DATE' accepts |
86 |
|
//config: a rather weird MMDDhhmm[[YY]YY][.ss] format with completely |
87 |
|
//config: unnatural placement of year between minutes and seconds. |
88 |
|
//config: date -s (and other commands like touch -d) use more sensible |
89 |
|
//config: formats (for one, ISO format YYYY-MM-DD hh:mm:ss.ssssss). |
90 |
|
//config: |
91 |
|
//config: With this option off, 'date DATE' is 'date -s DATE' support |
92 |
|
//config: the same format. With it on, 'date DATE' additionally supports |
93 |
|
//config: MMDDhhmm[[YY]YY][.ss] format. |
94 |
|
|
95 |
#include "libbb.h" |
#include "libbb.h" |
96 |
|
#if ENABLE_FEATURE_DATE_NANO |
97 |
|
# include <sys/syscall.h> |
98 |
|
#endif |
99 |
|
|
100 |
enum { |
enum { |
101 |
OPT_RFC2822 = (1 << 0), /* R */ |
OPT_RFC2822 = (1 << 0), /* R */ |
128 |
int date_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
int date_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
129 |
int date_main(int argc UNUSED_PARAM, char **argv) |
int date_main(int argc UNUSED_PARAM, char **argv) |
130 |
{ |
{ |
131 |
|
struct timespec ts; |
132 |
struct tm tm_time; |
struct tm tm_time; |
133 |
char buf_fmt_dt2str[64]; |
char buf_fmt_dt2str[64]; |
|
time_t tm; |
|
134 |
unsigned opt; |
unsigned opt; |
135 |
int ifmt = -1; |
int ifmt = -1; |
136 |
char *date_str; |
char *date_str; |
205 |
if (opt & OPT_REFERENCE) { |
if (opt & OPT_REFERENCE) { |
206 |
struct stat statbuf; |
struct stat statbuf; |
207 |
xstat(filename, &statbuf); |
xstat(filename, &statbuf); |
208 |
tm = statbuf.st_mtime; |
ts.tv_sec = statbuf.st_mtime; |
209 |
|
#if ENABLE_FEATURE_DATE_NANO |
210 |
|
ts.tv_nsec = statbuf.st_mtim.tv_nsec; |
211 |
|
#endif |
212 |
} else { |
} else { |
213 |
time(&tm); |
#if ENABLE_FEATURE_DATE_NANO |
214 |
|
/* libc has incredibly messy way of doing this, |
215 |
|
* typically requiring -lrt. We just skip all this mess */ |
216 |
|
syscall(__NR_clock_gettime, CLOCK_REALTIME, &ts); |
217 |
|
#else |
218 |
|
time(&ts.tv_sec); |
219 |
|
#endif |
220 |
} |
} |
221 |
localtime_r(&tm, &tm_time); |
localtime_r(&ts.tv_sec, &tm_time); |
222 |
|
|
223 |
/* If date string is given, update tm_time, and maybe set date */ |
/* If date string is given, update tm_time, and maybe set date */ |
224 |
if (date_str != NULL) { |
if (date_str != NULL) { |
237 |
|
|
238 |
/* Correct any day of week and day of year etc. fields */ |
/* Correct any day of week and day of year etc. fields */ |
239 |
tm_time.tm_isdst = -1; /* Be sure to recheck dst */ |
tm_time.tm_isdst = -1; /* Be sure to recheck dst */ |
240 |
tm = validate_tm_time(date_str, &tm_time); |
ts.tv_sec = validate_tm_time(date_str, &tm_time); |
241 |
|
|
242 |
maybe_set_utc(opt); |
maybe_set_utc(opt); |
243 |
|
|
244 |
/* if setting time, set it */ |
/* if setting time, set it */ |
245 |
if ((opt & OPT_SET) && stime(&tm) < 0) { |
if ((opt & OPT_SET) && stime(&ts.tv_sec) < 0) { |
246 |
bb_perror_msg("can't set date"); |
bb_perror_msg("can't set date"); |
247 |
} |
} |
248 |
} |
} |
275 |
fmt_dt2str = (char*)"%a %b %e %H:%M:%S %Z %Y"; |
fmt_dt2str = (char*)"%a %b %e %H:%M:%S %Z %Y"; |
276 |
} |
} |
277 |
} |
} |
278 |
|
#if ENABLE_FEATURE_DATE_NANO |
279 |
|
else { |
280 |
|
/* User-specified fmt_dt2str */ |
281 |
|
/* Search for and process "%N" */ |
282 |
|
char *p = fmt_dt2str; |
283 |
|
while ((p = strchr(p, '%')) != NULL) { |
284 |
|
int n, m; |
285 |
|
unsigned pres, scale; |
286 |
|
|
287 |
|
p++; |
288 |
|
if (*p == '%') { |
289 |
|
p++; |
290 |
|
continue; |
291 |
|
} |
292 |
|
n = strspn(p, "0123456789"); |
293 |
|
if (p[n] != 'N') { |
294 |
|
p += n; |
295 |
|
continue; |
296 |
|
} |
297 |
|
/* We have "%[nnn]N" */ |
298 |
|
p[-1] = '\0'; |
299 |
|
p[n] = '\0'; |
300 |
|
scale = 1; |
301 |
|
pres = 9; |
302 |
|
if (n) { |
303 |
|
pres = xatoi_u(p); |
304 |
|
if (pres == 0) |
305 |
|
pres = 9; |
306 |
|
m = 9 - pres; |
307 |
|
while (--m >= 0) |
308 |
|
scale *= 10; |
309 |
|
} |
310 |
|
|
311 |
|
m = p - fmt_dt2str; |
312 |
|
p += n + 1; |
313 |
|
fmt_dt2str = xasprintf("%s%0*u%s", fmt_dt2str, pres, (unsigned)ts.tv_nsec / scale, p); |
314 |
|
p = fmt_dt2str + m; |
315 |
|
} |
316 |
|
} |
317 |
|
#endif |
318 |
|
|
319 |
#define date_buf bb_common_bufsiz1 |
#define date_buf bb_common_bufsiz1 |
320 |
if (*fmt_dt2str == '\0') { |
if (*fmt_dt2str == '\0') { |