diff options
Diffstat (limited to 'coreutils/date.c')
-rw-r--r-- | coreutils/date.c | 104 |
1 files changed, 98 insertions, 6 deletions
diff --git a/coreutils/date.c b/coreutils/date.c index 4e5b3b0b8..3d78a5336 100644 --- a/coreutils/date.c +++ b/coreutils/date.c | |||
@@ -51,6 +51,47 @@ | |||
51 | * and does not support -Ins | 51 | * and does not support -Ins |
52 | * -D FMT is a bbox extension for _input_ conversion of -d DATE | 52 | * -D FMT is a bbox extension for _input_ conversion of -d DATE |
53 | */ | 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 | |||
54 | #include "libbb.h" | 95 | #include "libbb.h" |
55 | 96 | ||
56 | enum { | 97 | enum { |
@@ -84,9 +125,9 @@ static const char date_longopts[] ALIGN1 = | |||
84 | int date_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 125 | int date_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
85 | int date_main(int argc UNUSED_PARAM, char **argv) | 126 | int date_main(int argc UNUSED_PARAM, char **argv) |
86 | { | 127 | { |
128 | struct timespec ts; | ||
87 | struct tm tm_time; | 129 | struct tm tm_time; |
88 | char buf_fmt_dt2str[64]; | 130 | char buf_fmt_dt2str[64]; |
89 | time_t tm; | ||
90 | unsigned opt; | 131 | unsigned opt; |
91 | int ifmt = -1; | 132 | int ifmt = -1; |
92 | char *date_str; | 133 | char *date_str; |
@@ -161,11 +202,22 @@ int date_main(int argc UNUSED_PARAM, char **argv) | |||
161 | if (opt & OPT_REFERENCE) { | 202 | if (opt & OPT_REFERENCE) { |
162 | struct stat statbuf; | 203 | struct stat statbuf; |
163 | xstat(filename, &statbuf); | 204 | xstat(filename, &statbuf); |
164 | tm = statbuf.st_mtime; | 205 | ts.tv_sec = statbuf.st_mtime; |
206 | #if ENABLE_FEATURE_DATE_NANO | ||
207 | # if defined __GLIBC__ && !defined __UCLIBC__ | ||
208 | ts.tv_nsec = statbuf.st_mtim.tv_nsec; | ||
209 | # else | ||
210 | ts.tv_nsec = statbuf.st_mtimensec; | ||
211 | # endif | ||
212 | #endif | ||
165 | } else { | 213 | } else { |
166 | time(&tm); | 214 | #if ENABLE_FEATURE_DATE_NANO |
215 | clock_gettime(CLOCK_REALTIME, &ts); | ||
216 | #else | ||
217 | time(&ts.tv_nsec); | ||
218 | #endif | ||
167 | } | 219 | } |
168 | localtime_r(&tm, &tm_time); | 220 | localtime_r(&ts.tv_sec, &tm_time); |
169 | 221 | ||
170 | /* If date string is given, update tm_time, and maybe set date */ | 222 | /* If date string is given, update tm_time, and maybe set date */ |
171 | if (date_str != NULL) { | 223 | if (date_str != NULL) { |
@@ -184,12 +236,12 @@ int date_main(int argc UNUSED_PARAM, char **argv) | |||
184 | 236 | ||
185 | /* Correct any day of week and day of year etc. fields */ | 237 | /* Correct any day of week and day of year etc. fields */ |
186 | tm_time.tm_isdst = -1; /* Be sure to recheck dst */ | 238 | tm_time.tm_isdst = -1; /* Be sure to recheck dst */ |
187 | tm = validate_tm_time(date_str, &tm_time); | 239 | ts.tv_sec = validate_tm_time(date_str, &tm_time); |
188 | 240 | ||
189 | maybe_set_utc(opt); | 241 | maybe_set_utc(opt); |
190 | 242 | ||
191 | /* if setting time, set it */ | 243 | /* if setting time, set it */ |
192 | if ((opt & OPT_SET) && stime(&tm) < 0) { | 244 | if ((opt & OPT_SET) && stime(&ts.tv_sec) < 0) { |
193 | bb_perror_msg("can't set date"); | 245 | bb_perror_msg("can't set date"); |
194 | } | 246 | } |
195 | } | 247 | } |
@@ -222,6 +274,46 @@ int date_main(int argc UNUSED_PARAM, char **argv) | |||
222 | fmt_dt2str = (char*)"%a %b %e %H:%M:%S %Z %Y"; | 274 | fmt_dt2str = (char*)"%a %b %e %H:%M:%S %Z %Y"; |
223 | } | 275 | } |
224 | } | 276 | } |
277 | #if ENABLE_FEATURE_DATE_NANO | ||
278 | else { | ||
279 | /* User-specified fmt_dt2str */ | ||
280 | /* Search for and process "%N" */ | ||
281 | char *p = fmt_dt2str; | ||
282 | while ((p = strchr(p, '%')) != NULL) { | ||
283 | int n, m; | ||
284 | unsigned pres, scale; | ||
285 | |||
286 | p++; | ||
287 | if (*p == '%') { | ||
288 | p++; | ||
289 | continue; | ||
290 | } | ||
291 | n = strspn(p, "0123456789"); | ||
292 | if (p[n] != 'N') { | ||
293 | p += n; | ||
294 | continue; | ||
295 | } | ||
296 | /* We have "%[nnn]N" */ | ||
297 | p[-1] = '\0'; | ||
298 | p[n] = '\0'; | ||
299 | scale = 1; | ||
300 | pres = 9; | ||
301 | if (n) { | ||
302 | pres = xatoi_u(p); | ||
303 | if (pres == 0) | ||
304 | pres = 9; | ||
305 | m = 9 - pres; | ||
306 | while (--m >= 0) | ||
307 | scale *= 10; | ||
308 | } | ||
309 | |||
310 | m = p - fmt_dt2str; | ||
311 | p += n + 1; | ||
312 | fmt_dt2str = xasprintf("%s%0*u%s", fmt_dt2str, pres, (unsigned)ts.tv_nsec / scale, p); | ||
313 | p = fmt_dt2str + m; | ||
314 | } | ||
315 | } | ||
316 | #endif | ||
225 | 317 | ||
226 | #define date_buf bb_common_bufsiz1 | 318 | #define date_buf bb_common_bufsiz1 |
227 | if (*fmt_dt2str == '\0') { | 319 | if (*fmt_dt2str == '\0') { |