9e5605ca7f9e1ade67f7d960fb55034c52ddea1e
[platform/upstream/coreutils.git] / src / date.c
1 /* date - print or set the system date and time
2    Copyright (C) 1989, 1991 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
17
18 /* Options:
19    -d DATESTR   Display the date DATESTR.
20    -s DATESTR   Set the date to DATESTR.
21    -u           Display or set the date in universal instead of local time.
22    +FORMAT      Specify custom date output format, described below.
23    MMDDhhmm[[CC]YY][.ss]        Set the date in the format described below.
24
25    If one non-option argument is given, it is used as the date to which
26    to set the system clock, and must have the format:
27    MM   month (01..12)
28    DD   day in month (01..31)
29    hh   hour (00..23)
30    mm   minute (00..59)
31    CC   first 2 digits of year (optional, defaults to current) (00..99)
32    YY   last 2 digits of year (optional, defaults to current) (00..99)
33    ss   second (00..61)
34
35    If a non-option argument that starts with a `+' is specified, it
36    is used to control the format in which the date is printed; it
37    can contain any of the `%' substitutions allowed by the strftime
38    function.  A newline is always added at the end of the output.
39
40    David MacKenzie <djm@gnu.ai.mit.edu> */
41
42 #ifdef HAVE_CONFIG_H
43 #if defined (CONFIG_BROKETS)
44 /* We use <config.h> instead of "config.h" so that a compilation
45    using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
46    (which it would do because it found this file in $srcdir).  */
47 #include <config.h>
48 #else
49 #include "config.h"
50 #endif
51 #endif
52
53 #include <stdio.h>
54 #include <getopt.h>
55 #include <sys/types.h>
56
57 #include "version.h"
58 #include "system.h"
59
60 #ifdef TM_IN_SYS_TIME
61 #include <sys/time.h>
62 #else
63 #include <time.h>
64 #endif
65
66 #ifndef STDC_HEADERS
67 time_t mktime ();
68 size_t strftime ();
69 time_t time ();
70 #endif
71
72 int putenv ();
73 int stime ();
74
75 char *xrealloc ();
76 time_t get_date ();
77 time_t posixtime ();
78 void error ();
79
80 static void show_date ();
81 static void usage ();
82
83 /* putenv string to use Universal Coordinated Time.
84    POSIX.2 says it should be "TZ=UCT0" or "TZ=GMT0". */
85 #ifndef TZ_UCT
86 #if defined(hpux) || defined(__hpux__) || defined(ultrix) || defined(__ultrix__) || defined(USG)
87 #define TZ_UCT "TZ=GMT0"
88 #else
89 #define TZ_UCT "TZ="
90 #endif
91 #endif
92
93 /* The name this program was run with, for error messages. */
94 char *program_name;
95
96 /* If non-zero, display usage information and exit.  */
97 static int show_help;
98
99 /* If non-zero, print the version on standard output and exit.  */
100 static int show_version;
101
102 static struct option const long_options[] =
103 {
104   {"date", required_argument, NULL, 'd'},
105   {"help", no_argument, &show_help, 1},
106   {"set", required_argument, NULL, 's'},
107   {"uct", no_argument, NULL, 'u'},
108   {"universal", no_argument, NULL, 'u'},
109   {"version", no_argument, &show_version, 1},
110   {NULL, 0, NULL, 0}
111 };
112
113 void
114 main (argc, argv)
115      int argc;
116      char **argv;
117 {
118   int optc;
119   char *datestr = NULL;
120   time_t when;
121   int set_date = 0;
122   int universal_time = 0;
123
124   program_name = argv[0];
125
126   while ((optc = getopt_long (argc, argv, "d:s:u", long_options, (int *) 0))
127          != EOF)
128     switch (optc)
129       {
130       case 0:
131         break;
132       case 'd':
133         datestr = optarg;
134         break;
135       case 's':
136         datestr = optarg;
137         set_date = 1;
138         break;
139       case 'u':
140         universal_time = 1;
141         break;
142       default:
143         usage (1);
144       }
145
146   if (show_version)
147     {
148       printf ("%s\n", version_string);
149       exit (0);
150     }
151
152   if (show_help)
153     usage (0);
154
155   if (argc - optind > 1)
156     usage (1);
157
158   if (universal_time && putenv (TZ_UCT) != 0)
159     error (1, 0, "virtual memory exhausted");
160
161   time (&when);
162
163   if (datestr)
164     when = get_date (datestr, NULL);
165
166   if (argc - optind == 1 && argv[optind][0] != '+')
167     {
168       when = posixtime (argv[optind]);
169       set_date = 1;
170     }
171
172   if (when == -1)
173     error (1, 0, "invalid date");
174
175   if (set_date && stime (&when) == -1)
176     error (0, errno, "cannot set date");
177
178   if (argc - optind == 1 && argv[optind][0] == '+')
179     show_date (argv[optind] + 1, when);
180   else
181     show_date ((char *) NULL, when);
182
183   exit (0);
184 }
185
186 /* Display the date and/or time in WHEN according to the format specified
187    in FORMAT, followed by a newline.  If FORMAT is NULL, use the
188    standard output format (ctime style but with a timezone inserted). */
189
190 static void
191 show_date (format, when)
192      char *format;
193      time_t when;
194 {
195   struct tm *tm;
196   char *out = NULL;
197   size_t out_length = 0;
198
199   tm = localtime (&when);
200
201   if (format == NULL)
202     /* Print the date in the default format.  Vanilla ANSI C strftime
203        doesn't support %e, but POSIX requires it.  If you don't use
204        a GNU strftime, make sure yours supports %e.  */
205     format = "%a %b %e %H:%M:%S %Z %Y";
206   else if (*format == '\0')
207     {
208       printf ("\n");
209       return;
210     }
211
212   do
213     {
214       out_length += 200;
215       out = (char *) xrealloc (out, out_length);
216     }
217   while (strftime (out, out_length, format, tm) == 0);
218
219   printf ("%s\n", out);
220   free (out);
221 }
222
223 static void
224 usage (status)
225      int status;
226 {
227   fprintf (status == 0 ? stdout : stderr, "\
228 Usage: %s [OPTION]... [+FORMAT] [MMDDhhmm[[CC]YY][.ss]]\n\
229 ",
230            program_name);
231
232   if (status != 0)
233     fprintf (stderr, "Try `%s --help' for more information.\n",
234              program_name);
235   else
236     {
237       printf ("\
238 \n\
239   -d, --date STRING        display time described by STRING, not `now'\n\
240   -s, --set STRING         set time described by STRING\n\
241   -u, --uct, --universal   print or set Universal Coordinated Time\n\
242       --help               display this help and exit\n\
243       --version            output version information and exit\n\
244 ");
245       printf ("\
246 \n\
247 FORMAT controls the output.  Interpreted sequences are:\n\
248 \n\
249   %%%%   a literal %%\n\
250   %%A   locale's full weekday name, variable length (Sunday..Saturday)\n\
251   %%B   locale's full month name, variable length (January..December)\n\
252   %%D   date (mm/dd/yy)\n\
253   %%H   hour (00..23)\n\
254   %%I   hour (01..12)\n\
255   %%M   minute (00..59)\n\
256   %%S   second (00..61)\n\
257   %%T   time, 24-hour (hh:mm:ss)\n\
258   %%U   week number of year with Sunday as first day of week (00..53)\n\
259   %%W   week number of year with Monday as first day of week (00..53)\n\
260   %%X   locale's time representation (%%H:%%M:%%S)\n\
261   %%Y   year (1970...)\n\
262   %%Z   time zone (e.g., EDT), or nothing if no time zone is determinable\n\
263   %%a   locale's abbreviated weekday name (Sun..Sat)\n\
264   %%b   locale's abbreviated month name (Jan..Dec)\n\
265   %%c   locale's date and time (Sat Nov 04 12:02:33 EST 1989)\n\
266   %%d   day of month (01..31)\n\
267   %%h   same as %%b\n\
268   %%j   day of year (001..366)\n\
269   %%k   hour ( 0..23)\n\
270   %%l   hour ( 1..12)\n\
271   %%m   month (01..12)\n\
272   %%n   a newline\n\
273   %%p   locale's AM or PM\n\
274   %%r   time, 12-hour (hh:mm:ss [AP]M)\n\
275   %%t   a horizontal tab\n\
276   %%w   day of week (0..6)\n\
277   %%x   locale's date representation (mm/dd/yy)\n\
278   %%y   last two digits of year (00..99)\n\
279 ");
280     }
281
282   exit (status);
283 }