xref: /titanic_50/usr/src/lib/libcmd/common/date.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*3e14f97fSRoger A. Faulkner *          Copyright (c) 1992-2010 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6da2e3ebdSchin *                  Common Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10da2e3ebdSchin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebdSchin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                 Glenn Fowler <gsf@research.att.com>                  *
18da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
19da2e3ebdSchin *                                                                      *
20da2e3ebdSchin ***********************************************************************/
21da2e3ebdSchin #pragma prototyped
22da2e3ebdSchin /*
23da2e3ebdSchin  * Glenn Fowler
24da2e3ebdSchin  * AT&T Research
25da2e3ebdSchin  *
26da2e3ebdSchin  * date -- set/display date
27da2e3ebdSchin  */
28da2e3ebdSchin 
29da2e3ebdSchin static const char usage[] =
3034f9b3eeSRoland Mainz "[-?\n@(#)$Id: date (AT&T Research) 2009-03-03 $\n]"
31da2e3ebdSchin USAGE_LICENSE
32da2e3ebdSchin "[+NAME?date - set/list/convert dates]"
33da2e3ebdSchin "[+DESCRIPTION?\bdate\b sets the current date and time (with appropriate"
34da2e3ebdSchin "	privilege), lists the current date or file dates, or converts"
35da2e3ebdSchin "	dates.]"
36da2e3ebdSchin "[+?Most common \adate\a forms are recognized, including those for"
37da2e3ebdSchin "	\bcrontab\b(1), \bls\b(1), \btouch\b(1), and the default"
38da2e3ebdSchin "	output from \bdate\b itself.]"
39da2e3ebdSchin "[+?If the \adate\a operand consists of 4, 6, 8, 10 or 12 digits followed"
40da2e3ebdSchin "	by an optional \b.\b and two digits then it is interpreted as:"
41da2e3ebdSchin "	\aHHMM.SS\a, \addHHMM.SS\a, \ammddHHMM.SS\a, \ammddHHMMyy.SS\a or"
42da2e3ebdSchin "	\ayymmddHHMM.SS\a, or \ammddHHMMccyy.SS\a or \accyymmddHHMM.SS\a."
43da2e3ebdSchin "	Conflicting standards and practice allow a leading or trailing"
44da2e3ebdSchin "	2 or 4 digit year for the 10 and 12 digit forms; the X/Open trailing"
45da2e3ebdSchin "	form is used to disambiguate (\btouch\b(1) uses the leading form.)"
46da2e3ebdSchin "	Avoid the 10 digit form to avoid confusion. The digit fields are:]{"
47da2e3ebdSchin "		[+cc?Century - 1, 19-20.]"
48da2e3ebdSchin "		[+yy?Year in century, 00-99.]"
49da2e3ebdSchin "		[+mm?Month, 01-12.]"
50da2e3ebdSchin "		[+dd?Day of month, 01-31.]"
51da2e3ebdSchin "		[+HH?Hour, 00-23.]"
52da2e3ebdSchin "		[+MM?Minute, 00-59.]"
53da2e3ebdSchin "		[+SS?Seconds, 00-60.]"
54da2e3ebdSchin "}"
55da2e3ebdSchin "[+?If more than one \adate\a operand is specified then:]{"
56da2e3ebdSchin "		[+1.?Each operand sets the reference date for the next"
57da2e3ebdSchin "			operand.]"
58da2e3ebdSchin "		[+2.?The date is listed for each operand.]"
59da2e3ebdSchin "		[+3.?The system date is not set.]"
60da2e3ebdSchin "}"
61da2e3ebdSchin 
62da2e3ebdSchin "[a:access-time|atime?List file argument access times.]"
63da2e3ebdSchin "[c:change-time|ctime?List file argument change times.]"
64da2e3ebdSchin "[d:date?Use \adate\a as the current date and do not set the system"
65da2e3ebdSchin "	clock.]:[date]"
66da2e3ebdSchin "[e:epoch?Output the date in seconds since the epoch."
67da2e3ebdSchin "	Equivalent to \b--format=%s\b.]"
68da2e3ebdSchin "[E:elapsed?Interpret pairs of arguments as start and stop dates, sum the"
69da2e3ebdSchin "	differences between all pairs, and list the result as a"
70da2e3ebdSchin "	\bfmtelapsed\b(3) elapsed time on the standard output. If there are"
71da2e3ebdSchin "	an odd number of arguments then the last time argument is differenced"
72da2e3ebdSchin "	with the current time.]"
73da2e3ebdSchin "[f:format?Output the date according to the \bstrftime\b(3) \aformat\a."
74da2e3ebdSchin "	For backwards compatibility, a first argument of the form"
75da2e3ebdSchin "	\b+\b\aformat\a is equivalent to \b-f\b format."
76da2e3ebdSchin "	\aformat\a is in \bprintf\b(3) style, where %\afield\a names"
77da2e3ebdSchin "	a fixed size field, zero padded if necessary,"
78da2e3ebdSchin "	and \\\ac\a and \\\annn\a sequences are as in C. Invalid"
79da2e3ebdSchin "	%\afield\a specifications and all other characters are copied"
80da2e3ebdSchin "	without change. \afield\a may be preceded by \b%-\b to turn off"
81da2e3ebdSchin "	padding or \b%_\b to pad with space, otherwise numeric fields"
82da2e3ebdSchin "	are padded with \b0\b and string fields are padded with space."
83da2e3ebdSchin "	\afield\a may also be preceded by \bE\b for alternate era"
84da2e3ebdSchin "	representation or \bO\b for alternate digit representation (if"
85da2e3ebdSchin "	supported by the current locale.) Finally, an integral \awidth\a"
86da2e3ebdSchin "	preceding \afield\a truncates the field to \awidth\a characters."
87da2e3ebdSchin "	The fields are:]:[format]{"
88da2e3ebdSchin "		[+%?% character]"
89da2e3ebdSchin "		[+a?abbreviated weekday name]"
90da2e3ebdSchin "		[+A?full weekday name]"
91da2e3ebdSchin "		[+b?abbreviated month name]"
92da2e3ebdSchin "		[+c?\bctime\b(3) style date without the trailing newline]"
93da2e3ebdSchin "		[+C?2-digit century]"
94da2e3ebdSchin "		[+d?day of month number]"
95da2e3ebdSchin "		[+D?date as \amm/dd/yy\a]"
96da2e3ebdSchin "		[+e?blank padded day of month number]"
97da2e3ebdSchin "		[+E?unpadded day of month number]"
98da2e3ebdSchin "		[+f?locale default override date format]"
997c2fbfb3SApril Chin "		[+F?%ISO 8601:2000 standard date format; equivalent to Y-%m-%d]"
100da2e3ebdSchin "		[+g?\bls\b(1) \b-l\b recent date with \ahh:mm\a]"
101da2e3ebdSchin "		[+G?\bls\b(1) \b-l\b distant date with \ayyyy\a]"
102da2e3ebdSchin "		[+h?abbreviated month name]"
103da2e3ebdSchin "		[+H?24-hour clock hour]"
104da2e3ebdSchin "		[+i?international \bdate\b(1) date with time zone type name]"
105da2e3ebdSchin "		[+I?12-hour clock hour]"
106da2e3ebdSchin "		[+j?1-offset Julian date]"
107da2e3ebdSchin "		[+J?0-offset Julian date]"
108da2e3ebdSchin "		[+k?\bdate\b(1) style date]"
10934f9b3eeSRoland Mainz "		[+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]"
110da2e3ebdSchin "		[+l?\bls\b(1) \b-l\b date; equivalent to \b%Q/%g/%G/\b]"
1117c2fbfb3SApril Chin "		[+L?locale default date format]"
112da2e3ebdSchin "		[+m?month number]"
113da2e3ebdSchin "		[+M?minutes]"
114da2e3ebdSchin "		[+n?newline character]"
115da2e3ebdSchin "		[+N?nanoseconds 000000000-999999999]"
116da2e3ebdSchin "		[+p?meridian (e.g., \bAM\b or \bPM\b)]"
117da2e3ebdSchin "		[+q?time zone type name (nation code)]"
118da2e3ebdSchin "		[+Q?\a<del>recent<del>distant<del>\a: \a<del>\a is a unique"
119da2e3ebdSchin "			delimter character; \arecent\a format for recent"
120da2e3ebdSchin "			dates, \adistant\a format otherwise]"
121da2e3ebdSchin "		[+r?12-hour time as \ahh:mm:ss meridian\a]"
122da2e3ebdSchin "		[+R?24-hour time as \ahh:mm\a]"
123da2e3ebdSchin "		[+s?number of seconds since the epoch; \a.prec\a preceding"
124da2e3ebdSchin "			\bs\b appends \aprec\a nanosecond digits, \b9\b if"
125da2e3ebdSchin "			\aprec\a is omitted]"
126da2e3ebdSchin "		[+S?seconds 00-60]"
127da2e3ebdSchin "		[+t?tab character]"
128da2e3ebdSchin "		[+T?24-hour time as \ahh:mm:ss\a]"
129da2e3ebdSchin "		[+u?weekday number 1(Monday)-7]"
130da2e3ebdSchin "		[+U?week number with Sunday as the first day]"
131da2e3ebdSchin "		[+V?ISO week number (i18n is \afun\a)]"
132da2e3ebdSchin "		[+w?weekday number 0(Sunday)-6]"
133da2e3ebdSchin "		[+W?week number with Monday as the first day]"
134da2e3ebdSchin "		[+x?locale date style that includes month, day and year]"
135da2e3ebdSchin "		[+X?locale time style that includes hours and minutes]"
136da2e3ebdSchin "		[+y?2-digit year (you'll be sorry)]"
137da2e3ebdSchin "		[+Y?4-digit year]"
138da2e3ebdSchin "		[+z?time zone \aSHHMM\a west of GMT offset where S is"
139da2e3ebdSchin "			\b+\b or \b-\b]"
140da2e3ebdSchin "		[+Z?time zone name]"
141da2e3ebdSchin "		[+=[=]][-+]]flag?set (default or +) or clear (-) \aflag\a"
142da2e3ebdSchin "			for the remainder of \aformat\a, or for the remainder"
143da2e3ebdSchin "			of the process if \b==\b is specified. \aflag\a may be:]{"
144da2e3ebdSchin "			[+l?enable leap second adjustments]"
145da2e3ebdSchin "			[+n?convert \b%S\b as \b%S.%N\b]"
146da2e3ebdSchin "			[+u?UTC time zone]"
147da2e3ebdSchin "		}"
148da2e3ebdSchin "		[+#?equivalent to %s]"
149da2e3ebdSchin "		[+??alternate?use \aalternate\a format if a default format"
150da2e3ebdSchin "			override has not been specified, e.g., \bls\b(1) uses"
151da2e3ebdSchin "			\"%?%l\"; export TM_OPTIONS=\"format='\aoverride\a'\""
152da2e3ebdSchin "			to override the default]"
153da2e3ebdSchin "}"
154da2e3ebdSchin "[i:incremental|adjust?Set the system time in incrementatl adjustments to"
155da2e3ebdSchin "	avoid complete time shift shock. Negative adjustments still maintain"
156da2e3ebdSchin "	monotonic increasing time. Not available on all systems.]"
157da2e3ebdSchin "[L:last?List only the last time for multiple \adate\a operands.]"
158da2e3ebdSchin "[l:leap-seconds?Include leap seconds in time calculations. Leap seconds"
159da2e3ebdSchin "	after the ast library release date are not accounted for.]"
160da2e3ebdSchin "[m:modify-time|mtime?List file argument modify times.]"
161da2e3ebdSchin "[n!:network?Set network time.]"
162da2e3ebdSchin "[p:parse?Add \aformat\a to the list of \bstrptime\b(3) parse conversion"
163da2e3ebdSchin "	formats. \aformat\a follows the same conventions as the"
164da2e3ebdSchin "	\b--format\b option, with the addition of these format"
165da2e3ebdSchin "	fields:]:[format]{"
166da2e3ebdSchin "		[+|?If the format failed before this point then restart"
167da2e3ebdSchin "			the parse with the remaining format.]"
168da2e3ebdSchin "		[+&?Call the \btmdate\b(3) heuristic parser. This is"
169da2e3ebdSchin "			is the default when \b--parse\b is omitted.]"
170da2e3ebdSchin "}"
171da2e3ebdSchin "[s:show?Show the date without setting the system time.]"
172da2e3ebdSchin "[u:utc|gmt|zulu?Output dates in \acoordinated universal time\a (UTC).]"
173da2e3ebdSchin "[U:unelapsed?Interpret each argument as \bfmtelapsed\b(3) elapsed"
174da2e3ebdSchin "	time and list the \bstrelapsed\b(3) 1/\ascale\a seconds.]#[scale]"
175da2e3ebdSchin "[z:list-zones?List the known time zone table and exit. The table columns"
176da2e3ebdSchin "	are: country code, standard zone name, savings time zone name,"
177da2e3ebdSchin "	minutes west of \bUTC\b, and savings time minutes offset. Blank"
178da2e3ebdSchin "	or empty entries are listed as \b-\b.]"
179da2e3ebdSchin 
180da2e3ebdSchin "\n"
181da2e3ebdSchin "\n[ +format | date ... | file ... ]\n"
182da2e3ebdSchin "\n"
183da2e3ebdSchin 
184da2e3ebdSchin "[+SEE ALSO?\bcrontab\b(1), \bls\b(1), \btouch\b(1), \bfmtelapsed\b(3),"
185da2e3ebdSchin "	\bstrftime\b(3), \bstrptime\b(3), \btm\b(3)]"
186da2e3ebdSchin ;
187da2e3ebdSchin 
188da2e3ebdSchin #include <cmd.h>
189da2e3ebdSchin #include <ls.h>
190da2e3ebdSchin #include <proc.h>
191da2e3ebdSchin #include <tmx.h>
192da2e3ebdSchin #include <times.h>
193da2e3ebdSchin 
194da2e3ebdSchin typedef struct Fmt
195da2e3ebdSchin {
196da2e3ebdSchin 	struct Fmt*	next;
197da2e3ebdSchin 	char*		format;
198da2e3ebdSchin } Fmt_t;
199da2e3ebdSchin 
200da2e3ebdSchin #ifndef ENOSYS
201da2e3ebdSchin #define ENOSYS		EINVAL
202da2e3ebdSchin #endif
203da2e3ebdSchin 
204da2e3ebdSchin /*
205da2e3ebdSchin  * set the system clock
206da2e3ebdSchin  * the standards wimped out here
207da2e3ebdSchin  */
208da2e3ebdSchin 
209da2e3ebdSchin static int
settime(void * context,const char * cmd,Time_t now,int adjust,int network)2107c2fbfb3SApril Chin settime(void* context, const char* cmd, Time_t now, int adjust, int network)
211da2e3ebdSchin {
212da2e3ebdSchin 	char*		s;
213da2e3ebdSchin 	char**		argv;
214da2e3ebdSchin 	char*		args[5];
21534f9b3eeSRoland Mainz 	char		buf[1024];
216da2e3ebdSchin 
217da2e3ebdSchin 	if (!adjust && !network)
218da2e3ebdSchin 		return tmxsettime(now);
219da2e3ebdSchin 	argv = args;
220da2e3ebdSchin 	s = "/usr/bin/date";
221da2e3ebdSchin 	if (!streq(cmd, s) && (!eaccess(s, X_OK) || !eaccess(s+=4, X_OK)))
222da2e3ebdSchin 	{
223da2e3ebdSchin 		*argv++ = s;
224da2e3ebdSchin 		if (streq(astconf("UNIVERSE", NiL, NiL), "att"))
225da2e3ebdSchin 		{
2267c2fbfb3SApril Chin 			tmxfmt(buf, sizeof(buf), "%m%d%H" "%M%Y.%S", now);
227da2e3ebdSchin 			if (adjust)
228da2e3ebdSchin 				*argv++ = "-a";
229da2e3ebdSchin 		}
230da2e3ebdSchin 		else
231da2e3ebdSchin 		{
2327c2fbfb3SApril Chin 			tmxfmt(buf, sizeof(buf), "%Y%m%d%H" "%M.%S", now);
233da2e3ebdSchin 			if (network)
234da2e3ebdSchin 				*argv++ = "-n";
235da2e3ebdSchin 			if (tm_info.flags & TM_UTC)
236da2e3ebdSchin 				*argv++ = "-u";
237da2e3ebdSchin 		}
238da2e3ebdSchin 		*argv++ = buf;
239da2e3ebdSchin 		*argv = 0;
2407c2fbfb3SApril Chin 		if (!sh_run(context, argv - args, args))
241da2e3ebdSchin 			return 0;
242da2e3ebdSchin 	}
243da2e3ebdSchin 	return -1;
244da2e3ebdSchin }
245da2e3ebdSchin 
246da2e3ebdSchin /*
247da2e3ebdSchin  * convert s to Time_t with error checking
248da2e3ebdSchin  */
249da2e3ebdSchin 
250da2e3ebdSchin static Time_t
convert(register Fmt_t * f,char * s,Time_t now)251da2e3ebdSchin convert(register Fmt_t* f, char* s, Time_t now)
252da2e3ebdSchin {
253da2e3ebdSchin 	char*	t;
254da2e3ebdSchin 	char*	u;
255da2e3ebdSchin 
256da2e3ebdSchin 	do
257da2e3ebdSchin 	{
258da2e3ebdSchin 		now = tmxscan(s, &t, f->format, &u, now, 0);
259da2e3ebdSchin 		if (!*t && (!f->format || !*u))
260da2e3ebdSchin 			break;
261da2e3ebdSchin 	} while (f = f->next);
262da2e3ebdSchin 	if (!f || *t)
263da2e3ebdSchin 		error(3, "%s: invalid date specification", f ? t : s);
264da2e3ebdSchin 	return now;
265da2e3ebdSchin }
266da2e3ebdSchin 
267da2e3ebdSchin int
b_date(int argc,register char ** argv,void * context)268da2e3ebdSchin b_date(int argc, register char** argv, void* context)
269da2e3ebdSchin {
270da2e3ebdSchin 	register int	n;
271da2e3ebdSchin 	register char*	s;
272da2e3ebdSchin 	register Fmt_t*	f;
273da2e3ebdSchin 	char*		t;
274da2e3ebdSchin 	unsigned long	u;
275da2e3ebdSchin 	Time_t		now;
276da2e3ebdSchin 	Time_t		ts;
277da2e3ebdSchin 	Time_t		te;
278da2e3ebdSchin 	Time_t		e;
27934f9b3eeSRoland Mainz 	char		buf[1024];
280da2e3ebdSchin 	Fmt_t*		fmts;
281da2e3ebdSchin 	Fmt_t		fmt;
282da2e3ebdSchin 	struct stat	st;
283da2e3ebdSchin 
284da2e3ebdSchin 	char*		cmd = argv[0];	/* original command path	*/
285da2e3ebdSchin 	char*		format = 0;	/* tmxfmt() format		*/
286da2e3ebdSchin 	char*		string = 0;	/* date string			*/
287da2e3ebdSchin 	int		elapsed = 0;	/* args are start/stop pairs	*/
288da2e3ebdSchin 	int		filetime = 0;	/* use this st_ time field	*/
289da2e3ebdSchin 	int		increment = 0;	/* incrementally adjust time	*/
290da2e3ebdSchin 	int		last = 0;	/* display the last time arg	*/
291da2e3ebdSchin 	Tm_zone_t*	listzones = 0;	/* known time zone table	*/
292da2e3ebdSchin 	int		network = 0;	/* don't set network time	*/
293da2e3ebdSchin 	int		show = 0;	/* show date and don't set	*/
294da2e3ebdSchin 	int		unelapsed = 0;	/* fmtelapsed() => strelapsed	*/
295da2e3ebdSchin 
296da2e3ebdSchin 	cmdinit(argc, argv, context, ERROR_CATALOG, 0);
297da2e3ebdSchin 	tm_info.flags = TM_DATESTYLE;
298da2e3ebdSchin 	fmts = &fmt;
299da2e3ebdSchin 	fmt.format = "";
300da2e3ebdSchin 	fmt.next = 0;
301da2e3ebdSchin 	for (;;)
302da2e3ebdSchin 	{
303da2e3ebdSchin 		switch (optget(argv, usage))
304da2e3ebdSchin 		{
305da2e3ebdSchin 		case 'a':
306da2e3ebdSchin 		case 'c':
307da2e3ebdSchin 		case 'm':
308da2e3ebdSchin 			filetime = opt_info.option[1];
309da2e3ebdSchin 			continue;
310da2e3ebdSchin 		case 'd':
311da2e3ebdSchin 			string = opt_info.arg;
312da2e3ebdSchin 			show = 1;
313da2e3ebdSchin 			continue;
314da2e3ebdSchin 		case 'e':
315da2e3ebdSchin 			format = "%#";
316da2e3ebdSchin 			continue;
317da2e3ebdSchin 		case 'E':
318da2e3ebdSchin 			elapsed = 1;
319da2e3ebdSchin 			continue;
320da2e3ebdSchin 		case 'f':
321da2e3ebdSchin 			format = opt_info.arg;
322da2e3ebdSchin 			continue;
323da2e3ebdSchin 		case 'i':
324da2e3ebdSchin 			increment = 1;
325da2e3ebdSchin 			continue;
326da2e3ebdSchin 		case 'l':
327da2e3ebdSchin 			tm_info.flags |= TM_LEAP;
328da2e3ebdSchin 			continue;
329da2e3ebdSchin 		case 'L':
330da2e3ebdSchin 			last = 1;
331da2e3ebdSchin 			continue;
332da2e3ebdSchin 		case 'n':
333da2e3ebdSchin 			network = 1;
334da2e3ebdSchin 			continue;
335da2e3ebdSchin 		case 'p':
336da2e3ebdSchin 			if (!(f = newof(0, Fmt_t, 1, 0)))
337da2e3ebdSchin 				error(ERROR_SYSTEM|3, "out of space [format]");
338da2e3ebdSchin 			f->next = fmts;
339da2e3ebdSchin 			f->format = opt_info.arg;
340da2e3ebdSchin 			fmts = f;
341da2e3ebdSchin 			continue;
342da2e3ebdSchin 		case 's':
343da2e3ebdSchin 			show = 1;
344da2e3ebdSchin 			continue;
345da2e3ebdSchin 		case 'u':
346da2e3ebdSchin 			tm_info.flags |= TM_UTC;
347da2e3ebdSchin 			continue;
348da2e3ebdSchin 		case 'U':
349da2e3ebdSchin 			unelapsed = (int)opt_info.num;
350da2e3ebdSchin 			continue;
351da2e3ebdSchin 		case 'z':
352da2e3ebdSchin 			listzones = tm_data.zone;
353da2e3ebdSchin 			continue;
354da2e3ebdSchin 		case '?':
355da2e3ebdSchin 			error(ERROR_USAGE|4, "%s", opt_info.arg);
356da2e3ebdSchin 			continue;
357da2e3ebdSchin 		case ':':
358da2e3ebdSchin 			error(2, "%s", opt_info.arg);
359da2e3ebdSchin 			continue;
360da2e3ebdSchin 		}
361da2e3ebdSchin 		break;
362da2e3ebdSchin 	}
363da2e3ebdSchin 	argv += opt_info.index;
364da2e3ebdSchin 	if (error_info.errors)
365da2e3ebdSchin 		error(ERROR_USAGE|4, "%s", optusage(NiL));
366da2e3ebdSchin 	now = tmxgettime();
367da2e3ebdSchin 	if (listzones)
368da2e3ebdSchin 	{
369da2e3ebdSchin 		s = "-";
370da2e3ebdSchin 		while (listzones->standard)
371da2e3ebdSchin 		{
372da2e3ebdSchin 			if (listzones->type)
373da2e3ebdSchin 				s = listzones->type;
374da2e3ebdSchin 			sfprintf(sfstdout, "%3s %4s %4s %4d %4d\n", s, *listzones->standard ? listzones->standard : "-", listzones->daylight ? listzones->daylight : "-", listzones->west, listzones->dst);
375da2e3ebdSchin 			listzones++;
376da2e3ebdSchin 			show = 1;
377da2e3ebdSchin 		}
378da2e3ebdSchin 	}
379da2e3ebdSchin 	else if (elapsed)
380da2e3ebdSchin 	{
381da2e3ebdSchin 		e = 0;
382da2e3ebdSchin 		while (s = *argv++)
383da2e3ebdSchin 		{
384da2e3ebdSchin 			if (!(t = *argv++))
385da2e3ebdSchin 			{
386da2e3ebdSchin 				argv--;
387da2e3ebdSchin 				t = "now";
388da2e3ebdSchin 			}
389da2e3ebdSchin 			ts = convert(fmts, s, now);
390da2e3ebdSchin 			te = convert(fmts, t, now);
391da2e3ebdSchin 			if (te > ts)
392da2e3ebdSchin 				e += te - ts;
393da2e3ebdSchin 			else
394da2e3ebdSchin 				e += ts - te;
395da2e3ebdSchin 		}
396da2e3ebdSchin 		sfputr(sfstdout, fmtelapsed((unsigned long)tmxsec(e), 1), '\n');
397da2e3ebdSchin 		show = 1;
398da2e3ebdSchin 	}
399da2e3ebdSchin 	else if (unelapsed)
400da2e3ebdSchin 	{
401da2e3ebdSchin 		while (s = *argv++)
402da2e3ebdSchin 		{
403da2e3ebdSchin 			u = strelapsed(s, &t, unelapsed);
404da2e3ebdSchin 			if (*t)
405da2e3ebdSchin 				error(3, "%s: invalid elapsed time", s);
406da2e3ebdSchin 			sfprintf(sfstdout, "%lu\n", u);
407da2e3ebdSchin 		}
408da2e3ebdSchin 		show = 1;
409da2e3ebdSchin 	}
410da2e3ebdSchin 	else if (filetime)
411da2e3ebdSchin 	{
412da2e3ebdSchin 		if (!*argv)
413da2e3ebdSchin 			error(ERROR_USAGE|4, "%s", optusage(NiL));
414da2e3ebdSchin 		n = argv[1] != 0;
415da2e3ebdSchin 		while (s = *argv++)
416da2e3ebdSchin 		{
417da2e3ebdSchin 			if (stat(s, &st))
418da2e3ebdSchin 				error(2, "%s: not found", s);
419da2e3ebdSchin 			else
420da2e3ebdSchin 			{
421da2e3ebdSchin 				switch (filetime)
422da2e3ebdSchin 				{
423da2e3ebdSchin 				case 'a':
424da2e3ebdSchin 					now = tmxgetatime(&st);
425da2e3ebdSchin 					break;
426da2e3ebdSchin 				case 'c':
427da2e3ebdSchin 					now = tmxgetctime(&st);
428da2e3ebdSchin 					break;
429da2e3ebdSchin 				default:
430da2e3ebdSchin 					now = tmxgetmtime(&st);
431da2e3ebdSchin 					break;
432da2e3ebdSchin 				}
433da2e3ebdSchin 				tmxfmt(buf, sizeof(buf), format, now);
434da2e3ebdSchin 				if (n)
435da2e3ebdSchin 					sfprintf(sfstdout, "%s: %s\n", s, buf);
436da2e3ebdSchin 				else
437da2e3ebdSchin 					sfprintf(sfstdout, "%s\n", buf);
438da2e3ebdSchin 				show = 1;
439da2e3ebdSchin 			}
440da2e3ebdSchin 		}
441da2e3ebdSchin 	}
442da2e3ebdSchin 	else
443da2e3ebdSchin 	{
444da2e3ebdSchin 		if ((s = *argv) && !format && *s == '+')
445da2e3ebdSchin 		{
446da2e3ebdSchin 			format = s + 1;
447da2e3ebdSchin 			argv++;
448da2e3ebdSchin 			s = *argv;
449da2e3ebdSchin 		}
450da2e3ebdSchin 		if (s || (s = string))
451da2e3ebdSchin 		{
452da2e3ebdSchin 			if (*argv && string)
453da2e3ebdSchin 				error(ERROR_USAGE|4, "%s", optusage(NiL));
454da2e3ebdSchin 			now = convert(fmts, s, now);
455da2e3ebdSchin 			if (*argv && (s = *++argv))
456da2e3ebdSchin 			{
457da2e3ebdSchin 				show = 1;
458da2e3ebdSchin 				do
459da2e3ebdSchin 				{
460da2e3ebdSchin 					if (!last)
461da2e3ebdSchin 					{
462da2e3ebdSchin 						tmxfmt(buf, sizeof(buf), format, now);
463da2e3ebdSchin 						sfprintf(sfstdout, "%s\n", buf);
464da2e3ebdSchin 					}
465da2e3ebdSchin 					now = convert(fmts, s, now);
466da2e3ebdSchin 				} while (s = *++argv);
467da2e3ebdSchin 			}
468da2e3ebdSchin 		}
469da2e3ebdSchin 		else
470da2e3ebdSchin 			show = 1;
471da2e3ebdSchin 		if (format || show)
472da2e3ebdSchin 		{
473da2e3ebdSchin 			tmxfmt(buf, sizeof(buf), format, now);
474da2e3ebdSchin 			sfprintf(sfstdout, "%s\n", buf);
475da2e3ebdSchin 		}
4767c2fbfb3SApril Chin 		else if (settime(context, cmd, now, increment, network))
477da2e3ebdSchin 			error(ERROR_SYSTEM|3, "cannot set system time");
478da2e3ebdSchin 	}
479da2e3ebdSchin 	while (fmts != &fmt)
480da2e3ebdSchin 	{
481da2e3ebdSchin 		f = fmts;
482da2e3ebdSchin 		fmts = fmts->next;
483da2e3ebdSchin 		free(f);
484da2e3ebdSchin 	}
485da2e3ebdSchin 	tm_info.flags = 0;
486da2e3ebdSchin 	if (show && sfsync(sfstdout))
487da2e3ebdSchin 		error(ERROR_system(0), "write error");
488da2e3ebdSchin 	return error_info.errors != 0;
489da2e3ebdSchin }
490