blob: 2df9e0cc7a63661d385b66d39a3b14d6ac7adf62 [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 Andersen2ce1edc1999-10-12 15:42:48 +000037const char date_usage[] = "Usage: date [OPTION]... [+FORMAT]\n"
38" 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
162void
163date_err(void) {
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000164 fprintf (stderr, "%s\n", date_usage);
165 exit( FALSE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000166}
167
168int
Eric Andersen4bea32a1999-10-06 00:30:51 +0000169date_main(int argc, char * * argv)
Eric Andersencc8ed391999-10-05 16:24:54 +0000170{
171 char *date_str = NULL;
172 char *date_fmt = NULL;
173 char *t_buff;
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000174 int i;
Eric Andersencc8ed391999-10-05 16:24:54 +0000175 int set_time = 0;
176 int rfc822 = 0;
177 int utc = 0;
178 int use_arg = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +0000179 time_t tm;
180 struct tm tm_time;
Eric Andersencc8ed391999-10-05 16:24:54 +0000181
182 /* Interpret command line args */
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000183 i = --argc;
184 argv++;
185 while (i > 0 && **argv) {
186 if (**argv == '-') {
187 while (i>0 && *++(*argv)) switch (**argv) {
188 case 'R':
189 rfc822 = 1;
190 break;
191 case 's':
192 set_time = 1;
193 if(date_str != NULL) date_err();
194 date_str = optarg;
195 break;
196 case 'u':
197 utc = 1;
198 if (putenv ("TZ=UTC0") != 0) {
199 fprintf(stderr,"date: memory exhausted\n");
200 exit( FALSE);
201 }
202 /* Look ma, no break. Don't fix it either. */
203 case 'd':
204 use_arg = 1;
205 if(date_str != NULL) date_err();
206 date_str = optarg;
207 break;
208 case '-':
209 date_err();
210 }
211 } else {
212 if ( (date_fmt == NULL) && (strcmp(*argv, "+")==0) )
213 date_fmt=*argv;
214 else if (date_str == NULL) {
215 set_time = 1;
216 date_str=*argv;
217 } else {
218 date_err();
219 }
220 }
221 i--;
222 argv++;
Eric Andersencc8ed391999-10-05 16:24:54 +0000223 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000224
225
226 /* Now we have parsed all the information except the date format
227 which depends on whether the clock is being set or read */
228
229 time(&tm);
230 memcpy(&tm_time, localtime(&tm), sizeof(tm_time));
231 /* Zero out fields - take her back to midnight!*/
232 if(date_str != NULL) {
233 tm_time.tm_sec = 0;
234 tm_time.tm_min = 0;
235 tm_time.tm_hour = 0;
236 }
237
238 /* Process any date input to UNIX time since 1 Jan 1970 */
239 if(date_str != NULL) {
240
241 if(strchr(date_str, ':') != NULL) {
242 date_conv_ftime(&tm_time, date_str);
243 } else {
244 date_conv_time(&tm_time, date_str);
245 }
246
247 /* Correct any day of week and day of year etc fields */
248 tm = mktime(&tm_time);
249 if (tm < 0 ) {
250 fprintf(stderr, "date: invalid date `%s'\n", date_str);
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000251 exit( FALSE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000252 }
253
254 /* if setting time, set it */
255 if(set_time) {
256 if( stime(&tm) < 0) {
257 fprintf(stderr, "date: can't set date.\n");
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000258 exit( FALSE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000259 }
260 }
261 }
262
263 /* Display output */
264
265 /* Deal with format string */
266 if(date_fmt == NULL) {
267 date_fmt = (rfc822
268 ? (utc
269 ? "%a, %_d %b %Y %H:%M:%S GMT"
270 : "%a, %_d %b %Y %H:%M:%S %z")
271 : "%a %b %e %H:%M:%S %Z %Y");
272
273 } else if ( *date_fmt == '\0' ) {
274 /* Imitate what GNU 'date' does with NO format string! */
275 printf ("\n");
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000276 exit( TRUE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000277 }
278
279 /* Handle special conversions */
280
281 if( strncmp( date_fmt, "%f", 2) == 0 ) {
282 date_fmt = "%Y.%m.%d-%H:%M:%S";
283 }
284
285 /* Print OUTPUT (after ALL that!) */
286 t_buff = malloc(201);
287 strftime(t_buff, 200, date_fmt, &tm_time);
288 printf("%s\n", t_buff);
289
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000290 exit( TRUE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000291
292}
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000293