blob: 51194848baebcdee22fc2a88cedb58f6f460059d [file] [log] [blame]
Eric Andersen2ce1edc1999-10-12 15:42:48 +00001/*
2 * Mini date implementation for busybox
3 *
4 * Copyright (C) 1999 by Erik Andersen <andersee@debian.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20*/
21
Eric Andersencc8ed391999-10-05 16:24:54 +000022#include "internal.h"
23#include <stdlib.h>
24#include <errno.h>
25#include <sys/time.h>
26#include <unistd.h>
27#include <time.h>
28#include <stdio.h>
Eric Andersencc8ed391999-10-05 16:24:54 +000029
30
31/* This 'date' command supports only 2 time setting formats,
32 all the GNU strftime stuff (its in libc, lets use it),
33 setting time using UTC and displaying int, as well as
34 an RFC 822 complient date output for shell scripting
35 mail commands */
36
Eric Andersene77ae3a1999-10-19 20:03:34 +000037static const char date_usage[] = "date [OPTION]... [+FORMAT]\n"
Eric Andersen2ce1edc1999-10-12 15:42:48 +000038" or: date [OPTION] [MMDDhhmm[[CC]YY][.ss]]\n"
39"Display the current time in the given FORMAT, or set the system date.\n"
40"\nOptions:\n\t-R\t\toutput RFC-822 compliant date string\n"
41"\t-s\t\tset time described by STRING\n"
42"\t-u\t\tprint or set Coordinated Universal Time\n";
Eric Andersencc8ed391999-10-05 16:24:54 +000043
44
45/* Input parsing code is always bulky - used heavy duty libc stuff as
46 much as possible, missed out a lot of bounds checking */
47
48/* Default input handling to save suprising some people */
49
50struct tm *
51date_conv_time(struct tm *tm_time, const char *t_string) {
52 int nr;
53
54 nr = sscanf(t_string, "%2d%2d%2d%2d%d",
55 &(tm_time->tm_mon),
56 &(tm_time->tm_mday),
57 &(tm_time->tm_hour),
58 &(tm_time->tm_min),
59 &(tm_time->tm_year));
60
61 if(nr < 4 || nr > 5) {
62 fprintf(stderr, "date: invalid date `%s'\n", t_string);
Eric Andersen2ce1edc1999-10-12 15:42:48 +000063 exit( FALSE);
Eric Andersencc8ed391999-10-05 16:24:54 +000064 }
65
66 /* correct for century - minor Y2K problem here? */
67 if(tm_time->tm_year >= 1900)
68 tm_time->tm_year -= 1900;
69 /* adjust date */
70 tm_time->tm_mon -= 1;
71
72 return(tm_time);
73
74}
75
76
77/* The new stuff for LRP */
78
79struct tm *
80date_conv_ftime(struct tm *tm_time, const char *t_string) {
81 struct tm itm_time, jtm_time, ktm_time, \
82 ltm_time, mtm_time, ntm_time;
83
84 itm_time = *tm_time;
85 jtm_time = *tm_time;
86 ktm_time = *tm_time;
87 ltm_time = *tm_time;
88 mtm_time = *tm_time;
89 ntm_time = *tm_time;
90
91 /* Parse input and assign appropriately to tm_time */
92
93 if(sscanf(t_string, "%d:%d:%d",
94 &itm_time.tm_hour,
95 &itm_time.tm_min,
96 &itm_time.tm_sec) == 3 ) {
97
98 *tm_time = itm_time;
99 return(tm_time);
100
101 } else if (sscanf(t_string, "%d:%d",
102 &jtm_time.tm_hour,
103 &jtm_time.tm_min) == 2) {
104
105 *tm_time = jtm_time;
106 return(tm_time);
107
108 } else if (sscanf(t_string, "%d.%d-%d:%d:%d",
109 &ktm_time.tm_mon,
110 &ktm_time.tm_mday,
111 &ktm_time.tm_hour,
112 &ktm_time.tm_min,
113 &ktm_time.tm_sec) == 5) {
114
115 ktm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
116 *tm_time = ktm_time;
117 return(tm_time);
118
119 } else if (sscanf(t_string, "%d.%d-%d:%d",
120 &ltm_time.tm_mon,
121 &ltm_time.tm_mday,
122 &ltm_time.tm_hour,
123 &ltm_time.tm_min) == 4) {
124
125 ltm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
126 *tm_time = ltm_time;
127 return(tm_time);
128
129 } else if (sscanf(t_string, "%d.%d.%d-%d:%d:%d",
130 &mtm_time.tm_year,
131 &mtm_time.tm_mon,
132 &mtm_time.tm_mday,
133 &mtm_time.tm_hour,
134 &mtm_time.tm_min,
135 &mtm_time.tm_sec) == 6) {
136
137 mtm_time.tm_year -= 1900; /* Adjust years */
138 mtm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
139 *tm_time = mtm_time;
140 return(tm_time);
141
142 } else if (sscanf(t_string, "%d.%d.%d-%d:%d",
143 &ntm_time.tm_year,
144 &ntm_time.tm_mon,
145 &ntm_time.tm_mday,
146 &ntm_time.tm_hour,
147 &ntm_time.tm_min) == 5) {
148 ntm_time.tm_year -= 1900; /* Adjust years */
149 ntm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
150 *tm_time = ntm_time;
151 return(tm_time);
152
153 }
154
155 fprintf(stderr, "date: invalid date `%s'\n", t_string);
156
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000157 exit( FALSE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000158
159}
160
161
Eric Andersencc8ed391999-10-05 16:24:54 +0000162int
Eric Andersen4bea32a1999-10-06 00:30:51 +0000163date_main(int argc, char * * argv)
Eric Andersencc8ed391999-10-05 16:24:54 +0000164{
165 char *date_str = NULL;
166 char *date_fmt = NULL;
167 char *t_buff;
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000168 int i;
Eric Andersencc8ed391999-10-05 16:24:54 +0000169 int set_time = 0;
170 int rfc822 = 0;
171 int utc = 0;
172 int use_arg = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +0000173 time_t tm;
174 struct tm tm_time;
Eric Andersencc8ed391999-10-05 16:24:54 +0000175
176 /* Interpret command line args */
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000177 i = --argc;
178 argv++;
179 while (i > 0 && **argv) {
180 if (**argv == '-') {
181 while (i>0 && *++(*argv)) switch (**argv) {
182 case 'R':
183 rfc822 = 1;
184 break;
185 case 's':
186 set_time = 1;
Eric Andersenb0e9a701999-10-18 22:28:26 +0000187 if(date_str != NULL) usage ( date_usage);
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000188 date_str = optarg;
189 break;
190 case 'u':
191 utc = 1;
192 if (putenv ("TZ=UTC0") != 0) {
193 fprintf(stderr,"date: memory exhausted\n");
194 exit( FALSE);
195 }
196 /* Look ma, no break. Don't fix it either. */
197 case 'd':
198 use_arg = 1;
Eric Andersenb0e9a701999-10-18 22:28:26 +0000199 if(date_str != NULL) usage ( date_usage);
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000200 date_str = optarg;
201 break;
202 case '-':
Eric Andersenb0e9a701999-10-18 22:28:26 +0000203 usage ( date_usage);
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000204 }
205 } else {
206 if ( (date_fmt == NULL) && (strcmp(*argv, "+")==0) )
207 date_fmt=*argv;
208 else if (date_str == NULL) {
209 set_time = 1;
210 date_str=*argv;
211 } else {
Eric Andersenb0e9a701999-10-18 22:28:26 +0000212 usage ( date_usage);
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000213 }
214 }
215 i--;
216 argv++;
Eric Andersencc8ed391999-10-05 16:24:54 +0000217 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000218
219
220 /* Now we have parsed all the information except the date format
221 which depends on whether the clock is being set or read */
222
223 time(&tm);
224 memcpy(&tm_time, localtime(&tm), sizeof(tm_time));
225 /* Zero out fields - take her back to midnight!*/
226 if(date_str != NULL) {
227 tm_time.tm_sec = 0;
228 tm_time.tm_min = 0;
229 tm_time.tm_hour = 0;
230 }
231
232 /* Process any date input to UNIX time since 1 Jan 1970 */
233 if(date_str != NULL) {
234
235 if(strchr(date_str, ':') != NULL) {
236 date_conv_ftime(&tm_time, date_str);
237 } else {
238 date_conv_time(&tm_time, date_str);
239 }
240
241 /* Correct any day of week and day of year etc fields */
242 tm = mktime(&tm_time);
243 if (tm < 0 ) {
244 fprintf(stderr, "date: invalid date `%s'\n", date_str);
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000245 exit( FALSE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000246 }
247
248 /* if setting time, set it */
249 if(set_time) {
250 if( stime(&tm) < 0) {
251 fprintf(stderr, "date: can't set date.\n");
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000252 exit( FALSE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000253 }
254 }
255 }
256
257 /* Display output */
258
259 /* Deal with format string */
260 if(date_fmt == NULL) {
261 date_fmt = (rfc822
262 ? (utc
263 ? "%a, %_d %b %Y %H:%M:%S GMT"
264 : "%a, %_d %b %Y %H:%M:%S %z")
265 : "%a %b %e %H:%M:%S %Z %Y");
266
267 } else if ( *date_fmt == '\0' ) {
268 /* Imitate what GNU 'date' does with NO format string! */
269 printf ("\n");
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000270 exit( TRUE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000271 }
272
273 /* Handle special conversions */
274
275 if( strncmp( date_fmt, "%f", 2) == 0 ) {
276 date_fmt = "%Y.%m.%d-%H:%M:%S";
277 }
278
279 /* Print OUTPUT (after ALL that!) */
280 t_buff = malloc(201);
281 strftime(t_buff, 200, date_fmt, &tm_time);
282 printf("%s\n", t_buff);
283
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000284 exit( TRUE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000285
286}
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000287