1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1992-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
20 ***********************************************************************/
26 * date -- set/display date
29 static const char usage
[] =
30 "[-?\n@(#)$Id: date (AT&T Research) 2009-03-03 $\n]"
32 "[+NAME?date - set/list/convert dates]"
33 "[+DESCRIPTION?\bdate\b sets the current date and time (with appropriate"
34 " privilege), lists the current date or file dates, or converts"
36 "[+?Most common \adate\a forms are recognized, including those for"
37 " \bcrontab\b(1), \bls\b(1), \btouch\b(1), and the default"
38 " output from \bdate\b itself.]"
39 "[+?If the \adate\a operand consists of 4, 6, 8, 10 or 12 digits followed"
40 " by an optional \b.\b and two digits then it is interpreted as:"
41 " \aHHMM.SS\a, \addHHMM.SS\a, \ammddHHMM.SS\a, \ammddHHMMyy.SS\a or"
42 " \ayymmddHHMM.SS\a, or \ammddHHMMccyy.SS\a or \accyymmddHHMM.SS\a."
43 " Conflicting standards and practice allow a leading or trailing"
44 " 2 or 4 digit year for the 10 and 12 digit forms; the X/Open trailing"
45 " form is used to disambiguate (\btouch\b(1) uses the leading form.)"
46 " Avoid the 10 digit form to avoid confusion. The digit fields are:]{"
47 " [+cc?Century - 1, 19-20.]"
48 " [+yy?Year in century, 00-99.]"
49 " [+mm?Month, 01-12.]"
50 " [+dd?Day of month, 01-31.]"
52 " [+MM?Minute, 00-59.]"
53 " [+SS?Seconds, 00-60.]"
55 "[+?If more than one \adate\a operand is specified then:]{"
56 " [+1.?Each operand sets the reference date for the next"
58 " [+2.?The date is listed for each operand.]"
59 " [+3.?The system date is not set.]"
62 "[a:access-time|atime?List file argument access times.]"
63 "[c:change-time|ctime?List file argument change times.]"
64 "[d:date?Use \adate\a as the current date and do not set the system"
66 "[e:epoch?Output the date in seconds since the epoch."
67 " Equivalent to \b--format=%s\b.]"
68 "[E:elapsed?Interpret pairs of arguments as start and stop dates, sum the"
69 " differences between all pairs, and list the result as a"
70 " \bfmtelapsed\b(3) elapsed time on the standard output. If there are"
71 " an odd number of arguments then the last time argument is differenced"
72 " with the current time.]"
73 "[f:format?Output the date according to the \bstrftime\b(3) \aformat\a."
74 " For backwards compatibility, a first argument of the form"
75 " \b+\b\aformat\a is equivalent to \b-f\b format."
76 " \aformat\a is in \bprintf\b(3) style, where %\afield\a names"
77 " a fixed size field, zero padded if necessary,"
78 " and \\\ac\a and \\\annn\a sequences are as in C. Invalid"
79 " %\afield\a specifications and all other characters are copied"
80 " without change. \afield\a may be preceded by \b%-\b to turn off"
81 " padding or \b%_\b to pad with space, otherwise numeric fields"
82 " are padded with \b0\b and string fields are padded with space."
83 " \afield\a may also be preceded by \bE\b for alternate era"
84 " representation or \bO\b for alternate digit representation (if"
85 " supported by the current locale.) Finally, an integral \awidth\a"
86 " preceding \afield\a truncates the field to \awidth\a characters."
87 " The fields are:]:[format]{"
89 " [+a?abbreviated weekday name]"
90 " [+A?full weekday name]"
91 " [+b?abbreviated month name]"
92 " [+c?\bctime\b(3) style date without the trailing newline]"
93 " [+C?2-digit century]"
94 " [+d?day of month number]"
95 " [+D?date as \amm/dd/yy\a]"
96 " [+e?blank padded day of month number]"
97 " [+E?unpadded day of month number]"
98 " [+f?locale default override date format]"
99 " [+F?%ISO 8601:2000 standard date format; equivalent to Y-%m-%d]"
100 " [+g?\bls\b(1) \b-l\b recent date with \ahh:mm\a]"
101 " [+G?\bls\b(1) \b-l\b distant date with \ayyyy\a]"
102 " [+h?abbreviated month name]"
103 " [+H?24-hour clock hour]"
104 " [+i?international \bdate\b(1) date with time zone type name]"
105 " [+I?12-hour clock hour]"
106 " [+j?1-offset Julian date]"
107 " [+J?0-offset Julian date]"
108 " [+k?\bdate\b(1) style date]"
109 " [+K?all numeric date; equivalent to \b%Y-%m-%d+%H:%M:%S\b; \b%_[EO]]K\b for space separator, %OK adds \b.%N\b, \b%EK\b adds \b%.N%z\b, \b%_EK\b adds \b.%N %z\b]"
110 " [+l?\bls\b(1) \b-l\b date; equivalent to \b%Q/%g/%G/\b]"
111 " [+L?locale default date format]"
114 " [+n?newline character]"
115 " [+N?nanoseconds 000000000-999999999]"
116 " [+p?meridian (e.g., \bAM\b or \bPM\b)]"
117 " [+q?time zone type name (nation code)]"
118 " [+Q?\a<del>recent<del>distant<del>\a: \a<del>\a is a unique"
119 " delimter character; \arecent\a format for recent"
120 " dates, \adistant\a format otherwise]"
121 " [+r?12-hour time as \ahh:mm:ss meridian\a]"
122 " [+R?24-hour time as \ahh:mm\a]"
123 " [+s?number of seconds since the epoch; \a.prec\a preceding"
124 " \bs\b appends \aprec\a nanosecond digits, \b9\b if"
125 " \aprec\a is omitted]"
126 " [+S?seconds 00-60]"
127 " [+t?tab character]"
128 " [+T?24-hour time as \ahh:mm:ss\a]"
129 " [+u?weekday number 1(Monday)-7]"
130 " [+U?week number with Sunday as the first day]"
131 " [+V?ISO week number (i18n is \afun\a)]"
132 " [+w?weekday number 0(Sunday)-6]"
133 " [+W?week number with Monday as the first day]"
134 " [+x?locale date style that includes month, day and year]"
135 " [+X?locale time style that includes hours and minutes]"
136 " [+y?2-digit year (you'll be sorry)]"
138 " [+z?time zone \aSHHMM\a west of GMT offset where S is"
140 " [+Z?time zone name]"
141 " [+=[=]][-+]]flag?set (default or +) or clear (-) \aflag\a"
142 " for the remainder of \aformat\a, or for the remainder"
143 " of the process if \b==\b is specified. \aflag\a may be:]{"
144 " [+l?enable leap second adjustments]"
145 " [+n?convert \b%S\b as \b%S.%N\b]"
146 " [+u?UTC time zone]"
148 " [+#?equivalent to %s]"
149 " [+??alternate?use \aalternate\a format if a default format"
150 " override has not been specified, e.g., \bls\b(1) uses"
151 " \"%?%l\"; export TM_OPTIONS=\"format='\aoverride\a'\""
152 " to override the default]"
154 "[i:incremental|adjust?Set the system time in incrementatl adjustments to"
155 " avoid complete time shift shock. Negative adjustments still maintain"
156 " monotonic increasing time. Not available on all systems.]"
157 "[L:last?List only the last time for multiple \adate\a operands.]"
158 "[l:leap-seconds?Include leap seconds in time calculations. Leap seconds"
159 " after the ast library release date are not accounted for.]"
160 "[m:modify-time|mtime?List file argument modify times.]"
161 "[n!:network?Set network time.]"
162 "[p:parse?Add \aformat\a to the list of \bstrptime\b(3) parse conversion"
163 " formats. \aformat\a follows the same conventions as the"
164 " \b--format\b option, with the addition of these format"
165 " fields:]:[format]{"
166 " [+|?If the format failed before this point then restart"
167 " the parse with the remaining format.]"
168 " [+&?Call the \btmdate\b(3) heuristic parser. This is"
169 " is the default when \b--parse\b is omitted.]"
171 "[s:show?Show the date without setting the system time.]"
172 "[u:utc|gmt|zulu?Output dates in \acoordinated universal time\a (UTC).]"
173 "[U:unelapsed?Interpret each argument as \bfmtelapsed\b(3) elapsed"
174 " time and list the \bstrelapsed\b(3) 1/\ascale\a seconds.]#[scale]"
175 "[z:list-zones?List the known time zone table and exit. The table columns"
176 " are: country code, standard zone name, savings time zone name,"
177 " minutes west of \bUTC\b, and savings time minutes offset. Blank"
178 " or empty entries are listed as \b-\b.]"
181 "\n[ +format | date ... | file ... ]\n"
184 "[+SEE ALSO?\bcrontab\b(1), \bls\b(1), \btouch\b(1), \bfmtelapsed\b(3),"
185 " \bstrftime\b(3), \bstrptime\b(3), \btm\b(3)]"
201 #define ENOSYS EINVAL
205 * set the system clock
206 * the standards wimped out here
210 settime(void* context
, const char* cmd
, Time_t now
, int adjust
, int network
)
217 if (!adjust
&& !network
)
218 return tmxsettime(now
);
221 if (!streq(cmd
, s
) && (!eaccess(s
, X_OK
) || !eaccess(s
+=4, X_OK
)))
224 if (streq(astconf("UNIVERSE", NiL
, NiL
), "att"))
226 tmxfmt(buf
, sizeof(buf
), "%m%d%H" "%M%Y.%S", now
);
232 tmxfmt(buf
, sizeof(buf
), "%Y%m%d%H" "%M.%S", now
);
235 if (tm_info
.flags
& TM_UTC
)
240 if (!sh_run(context
, argv
- args
, args
))
247 * convert s to Time_t with error checking
251 convert(register Fmt_t
* f
, char* s
, Time_t now
)
258 now
= tmxscan(s
, &t
, f
->format
, &u
, now
, 0);
259 if (!*t
&& (!f
->format
|| !*u
))
261 } while (f
= f
->next
);
263 error(3, "%s: invalid date specification", f
? t
: s
);
268 b_date(int argc
, register char** argv
, void* context
)
284 char* cmd
= argv
[0]; /* original command path */
285 char* format
= 0; /* tmxfmt() format */
286 char* string
= 0; /* date string */
287 int elapsed
= 0; /* args are start/stop pairs */
288 int filetime
= 0; /* use this st_ time field */
289 int increment
= 0; /* incrementally adjust time */
290 int last
= 0; /* display the last time arg */
291 Tm_zone_t
* listzones
= 0; /* known time zone table */
292 int network
= 0; /* don't set network time */
293 int show
= 0; /* show date and don't set */
294 int unelapsed
= 0; /* fmtelapsed() => strelapsed */
296 cmdinit(argc
, argv
, context
, ERROR_CATALOG
, 0);
297 tm_info
.flags
= TM_DATESTYLE
;
303 switch (optget(argv
, usage
))
308 filetime
= opt_info
.option
[1];
311 string
= opt_info
.arg
;
321 format
= opt_info
.arg
;
327 tm_info
.flags
|= TM_LEAP
;
336 if (!(f
= newof(0, Fmt_t
, 1, 0)))
337 error(ERROR_SYSTEM
|3, "out of space [format]");
339 f
->format
= opt_info
.arg
;
346 tm_info
.flags
|= TM_UTC
;
349 unelapsed
= (int)opt_info
.num
;
352 listzones
= tm_data
.zone
;
355 error(ERROR_USAGE
|4, "%s", opt_info
.arg
);
358 error(2, "%s", opt_info
.arg
);
363 argv
+= opt_info
.index
;
364 if (error_info
.errors
)
365 error(ERROR_USAGE
|4, "%s", optusage(NiL
));
370 while (listzones
->standard
)
374 sfprintf(sfstdout
, "%3s %4s %4s %4d %4d\n", s
, *listzones
->standard
? listzones
->standard
: "-", listzones
->daylight
? listzones
->daylight
: "-", listzones
->west
, listzones
->dst
);
389 ts
= convert(fmts
, s
, now
);
390 te
= convert(fmts
, t
, now
);
396 sfputr(sfstdout
, fmtelapsed((unsigned long)tmxsec(e
), 1), '\n');
403 u
= strelapsed(s
, &t
, unelapsed
);
405 error(3, "%s: invalid elapsed time", s
);
406 sfprintf(sfstdout
, "%lu\n", u
);
413 error(ERROR_USAGE
|4, "%s", optusage(NiL
));
418 error(2, "%s: not found", s
);
424 now
= tmxgetatime(&st
);
427 now
= tmxgetctime(&st
);
430 now
= tmxgetmtime(&st
);
433 tmxfmt(buf
, sizeof(buf
), format
, now
);
435 sfprintf(sfstdout
, "%s: %s\n", s
, buf
);
437 sfprintf(sfstdout
, "%s\n", buf
);
444 if ((s
= *argv
) && !format
&& *s
== '+')
450 if (s
|| (s
= string
))
453 error(ERROR_USAGE
|4, "%s", optusage(NiL
));
454 now
= convert(fmts
, s
, now
);
455 if (*argv
&& (s
= *++argv
))
462 tmxfmt(buf
, sizeof(buf
), format
, now
);
463 sfprintf(sfstdout
, "%s\n", buf
);
465 now
= convert(fmts
, s
, now
);
466 } while (s
= *++argv
);
473 tmxfmt(buf
, sizeof(buf
), format
, now
);
474 sfprintf(sfstdout
, "%s\n", buf
);
476 else if (settime(context
, cmd
, now
, increment
, network
))
477 error(ERROR_SYSTEM
|3, "cannot set system time");
486 if (show
&& sfsync(sfstdout
))
487 error(ERROR_system(0), "write error");
488 return error_info
.errors
!= 0;