4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
30 * Copyright (c) 2012, Joyent, Inc. All rights reserved.
32 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
33 /* All Rights Reserved */
36 * University Copyright- Copyright (c) 1982, 1986, 1988
37 * The Regents of the University of California
40 * University Acknowledgment- Portions of this document are derived from
41 * software developed by the University of California, Berkeley, and its
46 * date - with format capabilities and international flair
58 #include <sys/types.h>
63 #define year_size(A) ((isleap(A)) ? 366 : 365)
64 static char buf
[BUFSIZ
];
65 static time_t clock_val
;
66 static short month_size
[12] =
67 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
68 static struct utmpx wtmpx
[2] = {
69 {"", "", OTIME_MSG
, 0, OLD_TIME
, 0, 0, 0},
70 {"", "", NTIME_MSG
, 0, NEW_TIME
, 0, 0, 0}
73 "usage:\tdate [-u] mmddHHMM[[cc]yy][.SS]\n\tdate [-Ru] [+format]\n"
74 "\tdate -a [-]sss[.fff]\n";
78 static int get_adj(char *, struct timeval
*);
79 static int setdate(struct tm
*, char *);
80 static void fmt_extensions(char *, size_t,
81 const char *, const struct timespec
*);
84 main(int argc
, char **argv
)
90 int c
, aflag
= 0, illflag
= 0;
93 (void) setlocale(LC_ALL
, "");
95 #if !defined(TEXT_DOMAIN)
96 #define TEXT_DOMAIN "SYS_TEST"
98 (void) textdomain(TEXT_DOMAIN
);
100 while ((c
= getopt(argc
, argv
, "a:uR")) != EOF
)
104 if (get_adj(optarg
, &tv
) < 0) {
105 (void) fprintf(stderr
,
106 gettext("date: invalid argument -- %s\n"),
122 argv
= &argv
[optind
];
124 /* -a is mutually exclusive with -u and -R */
131 (void) fprintf(stderr
, gettext(usage
));
135 if (clock_gettime(CLOCK_REALTIME
, &ts
) != 0) {
136 perror(gettext("date: Failed to obtain system time"));
139 clock_val
= ts
.tv_sec
;
142 if (adjtime(&tv
, 0) < 0) {
143 perror(gettext("date: Failed to adjust date"));
153 if (setdate(localtime(&clock_val
), argv
[0])) {
154 (void) fprintf(stderr
, gettext(usage
));
157 fmt
= nl_langinfo(_DATE_FMT
);
160 fmt
= "%a, %d %h %Y %H:%M:%S %z";
162 fmt
= nl_langinfo(_DATE_FMT
);
164 fmt_extensions(fmtbuf
, sizeof (fmtbuf
), fmt
, &ts
);
167 (void) putenv("TZ=GMT0");
169 tp
= gmtime(&clock_val
);
171 tp
= localtime(&clock_val
);
172 (void) memcpy(&tm
, tp
, sizeof (struct tm
));
173 (void) strftime(buf
, BUFSIZ
, fmtbuf
, &tm
);
181 setdate(struct tm
*current_date
, char *date
)
195 /* Parse date string */
196 if ((secptr
= strchr(date
, '.')) != NULL
&& strlen(&secptr
[1]) == 2 &&
197 isdigit(secptr
[1]) && isdigit(secptr
[2]) &&
198 (sec
= atoi(&secptr
[1])) >= 0 && sec
< 60)
199 secptr
[0] = '\0'; /* eat decimal point only on success */
203 for (i
= 0; i
< len
; i
++) {
204 if (!isdigit(date
[i
])) {
205 (void) fprintf(stderr
,
206 gettext("date: bad conversion\n"));
210 switch (strlen(date
)) {
217 * The YY format has the following representation:
218 * 00-68 = 2000 thru 2068
219 * 69-99 = 1969 thru 1999
221 if (atoi(&date
[8]) <= 68) {
222 yy
= 1900 + (atoi(&date
[8]) + 100);
224 yy
= 1900 + atoi(&date
[8]);
229 yy
= 1900 + current_date
->tm_year
;
232 yy
= 1900 + current_date
->tm_year
;
233 mm
= current_date
->tm_mon
+ 1; /* tm_mon goes from 1 to 11 */
234 dd
= current_date
->tm_mday
;
238 (void) fprintf(stderr
, gettext("date: bad conversion\n"));
242 min
= atoi(&date
[minidx
]);
244 hh
= atoi(&date
[minidx
-2]);
245 date
[minidx
-2] = '\0';
249 * if dd is 0 (not between 1 and 31), then
250 * read the value supplied by the user.
260 /* Validate date elements */
262 if (mm
>= 1 && mm
<= 12) {
263 dd_check
= month_size
[mm
- 1]; /* get days in this month */
264 if (mm
== 2 && isleap(yy
)) /* adjust for leap year */
267 if (!((mm
>= 1 && mm
<= 12) && (dd
>= 1 && dd
<= dd_check
) &&
268 (hh
>= 0 && hh
<= 23) && (min
>= 0 && min
<= 59))) {
269 (void) fprintf(stderr
, gettext("date: bad conversion\n"));
273 /* Build date and time number */
274 for (clock_val
= 0, i
= 1970; i
< yy
; i
++)
275 clock_val
+= year_size(i
);
276 /* Adjust for leap year */
277 if (isleap(yy
) && mm
>= 3)
279 /* Adjust for different month lengths */
281 clock_val
+= (time_t)month_size
[mm
- 1];
282 /* Load up the rest */
283 clock_val
+= (time_t)(dd
- 1);
285 clock_val
+= (time_t)hh
;
287 clock_val
+= (time_t)min
;
292 /* convert to GMT assuming standard time */
293 /* correction is made in localtime(3C) */
296 * call localtime to set up "timezone" variable applicable
297 * for clock_val time, to support Olson timezones which
298 * can allow timezone rules to change.
300 (void) localtime(&clock_val
);
302 clock_val
+= (time_t)timezone
;
304 /* correct if daylight savings time in effect */
306 if (localtime(&clock_val
)->tm_isdst
)
307 clock_val
= clock_val
- (time_t)(timezone
- altzone
);
310 (void) time(&wtmpx
[0].ut_xtime
);
311 if (stime(&clock_val
) < 0) {
316 /* correct the kernel's "gmt_lag" and the PC's RTC */
317 (void) system("/usr/sbin/rtc -c > /dev/null 2>&1");
319 (void) time(&wtmpx
[1].ut_xtime
);
320 (void) pututxline(&wtmpx
[0]);
321 (void) pututxline(&wtmpx
[1]);
322 (void) updwtmpx(WTMPX_FILE
, &wtmpx
[0]);
323 (void) updwtmpx(WTMPX_FILE
, &wtmpx
[1]);
328 get_adj(char *cp
, struct timeval
*tp
)
333 /* arg must be [-]sss[.fff] */
335 tp
->tv_sec
= tp
->tv_usec
= 0;
343 while (*cp
>= '0' && *cp
<= '9') {
345 tp
->tv_sec
+= *cp
++ - '0';
350 while (*cp
>= '0' && *cp
<= '9') {
351 tp
->tv_usec
+= (*cp
++ - '0') * mult
;
356 * if there's anything left in the string,
357 * the input was invalid.
369 * Extensions that cannot be interpreted by strftime are interpreted here.
372 fmt_extensions(char *fmtbuf
, size_t len
,
373 const char *fmt
, const struct timespec
*tsp
)
378 for (p
= fmt
, q
= fmtbuf
; *p
!= '\0' && q
< fmtbuf
+ len
; ++p
) {
383 q
+= snprintf(q
, len
- (q
- fmtbuf
),
384 "%09lu", tsp
->tv_nsec
);
391 if (q
< fmtbuf
+ len
)
394 fmtbuf
[len
- 1] = '\0';