xref: /onnv-gate/usr/src/cmd/mdb/common/libstand/ctime.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3*0Sstevel@tonic-gate  * Use is subject to license terms.
4*0Sstevel@tonic-gate  */
5*0Sstevel@tonic-gate 
6*0Sstevel@tonic-gate /*
7*0Sstevel@tonic-gate  * Copyright (c) 1980 Regents of the University of California.
8*0Sstevel@tonic-gate  * All rights reserved. The Berkeley software License Agreement
9*0Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
10*0Sstevel@tonic-gate  */
11*0Sstevel@tonic-gate 
12*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
13*0Sstevel@tonic-gate 
14*0Sstevel@tonic-gate /*
15*0Sstevel@tonic-gate  * This localtime is a modified version of offtime from libc, which does not
16*0Sstevel@tonic-gate  * bother to figure out the time zone from the kernel, from environment
17*0Sstevel@tonic-gate  * variables, or from Unix files.
18*0Sstevel@tonic-gate  */
19*0Sstevel@tonic-gate 
20*0Sstevel@tonic-gate #include <sys/types.h>
21*0Sstevel@tonic-gate #include <sys/salib.h>
22*0Sstevel@tonic-gate #include <tzfile.h>
23*0Sstevel@tonic-gate #include <errno.h>
24*0Sstevel@tonic-gate 
25*0Sstevel@tonic-gate static int mon_lengths[2][MONS_PER_YEAR] = {
26*0Sstevel@tonic-gate 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
27*0Sstevel@tonic-gate 	31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
28*0Sstevel@tonic-gate };
29*0Sstevel@tonic-gate 
30*0Sstevel@tonic-gate static int year_lengths[2] = {
31*0Sstevel@tonic-gate 	DAYS_PER_NYEAR, DAYS_PER_LYEAR
32*0Sstevel@tonic-gate };
33*0Sstevel@tonic-gate 
34*0Sstevel@tonic-gate struct tm *
35*0Sstevel@tonic-gate localtime(const time_t *clock)
36*0Sstevel@tonic-gate {
37*0Sstevel@tonic-gate 	struct tm *tmp;
38*0Sstevel@tonic-gate 	long days;
39*0Sstevel@tonic-gate 	long rem;
40*0Sstevel@tonic-gate 	int y;
41*0Sstevel@tonic-gate 	int yleap;
42*0Sstevel@tonic-gate 	int *ip;
43*0Sstevel@tonic-gate 	static struct tm tm;
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate 	tmp = &tm;
46*0Sstevel@tonic-gate 	days = *clock / SECS_PER_DAY;
47*0Sstevel@tonic-gate 	rem = *clock % SECS_PER_DAY;
48*0Sstevel@tonic-gate 	while (rem < 0) {
49*0Sstevel@tonic-gate 		rem += SECS_PER_DAY;
50*0Sstevel@tonic-gate 		--days;
51*0Sstevel@tonic-gate 	}
52*0Sstevel@tonic-gate 	while (rem >= SECS_PER_DAY) {
53*0Sstevel@tonic-gate 		rem -= SECS_PER_DAY;
54*0Sstevel@tonic-gate 		++days;
55*0Sstevel@tonic-gate 	}
56*0Sstevel@tonic-gate 	tmp->tm_hour = (int)(rem / SECS_PER_HOUR);
57*0Sstevel@tonic-gate 	rem = rem % SECS_PER_HOUR;
58*0Sstevel@tonic-gate 	tmp->tm_min = (int)(rem / SECS_PER_MIN);
59*0Sstevel@tonic-gate 	tmp->tm_sec = (int)(rem % SECS_PER_MIN);
60*0Sstevel@tonic-gate 	tmp->tm_wday = (int)((EPOCH_WDAY + days) % DAYS_PER_WEEK);
61*0Sstevel@tonic-gate 	if (tmp->tm_wday < 0)
62*0Sstevel@tonic-gate 		tmp->tm_wday += DAYS_PER_WEEK;
63*0Sstevel@tonic-gate 	y = EPOCH_YEAR;
64*0Sstevel@tonic-gate 	if (days >= 0) {
65*0Sstevel@tonic-gate 		for (;;) {
66*0Sstevel@tonic-gate 			yleap = isleap(y);
67*0Sstevel@tonic-gate 			if (days < (long)year_lengths[yleap])
68*0Sstevel@tonic-gate 				break;
69*0Sstevel@tonic-gate 			if (++y > 9999) {
70*0Sstevel@tonic-gate 				errno = EOVERFLOW;
71*0Sstevel@tonic-gate 				return (NULL);
72*0Sstevel@tonic-gate 			}
73*0Sstevel@tonic-gate 			days = days - (long)year_lengths[yleap];
74*0Sstevel@tonic-gate 		}
75*0Sstevel@tonic-gate 	} else {
76*0Sstevel@tonic-gate 		do {
77*0Sstevel@tonic-gate 			if (--y < 0) {
78*0Sstevel@tonic-gate 				errno = EOVERFLOW;
79*0Sstevel@tonic-gate 				return (NULL);
80*0Sstevel@tonic-gate 			}
81*0Sstevel@tonic-gate 			yleap = isleap(y);
82*0Sstevel@tonic-gate 			days = days + (long)year_lengths[yleap];
83*0Sstevel@tonic-gate 		} while (days < 0);
84*0Sstevel@tonic-gate 	}
85*0Sstevel@tonic-gate 	tmp->tm_year = y - TM_YEAR_BASE;
86*0Sstevel@tonic-gate 	tmp->tm_yday = (int)days;
87*0Sstevel@tonic-gate 	ip = mon_lengths[yleap];
88*0Sstevel@tonic-gate 	for (tmp->tm_mon = 0; days >= (long)ip[tmp->tm_mon]; ++(tmp->tm_mon))
89*0Sstevel@tonic-gate 		days = days - (long)ip[tmp->tm_mon];
90*0Sstevel@tonic-gate 	tmp->tm_mday = (int)(days + 1);
91*0Sstevel@tonic-gate 	tmp->tm_isdst = 0;
92*0Sstevel@tonic-gate 
93*0Sstevel@tonic-gate 	return (tmp);
94*0Sstevel@tonic-gate }
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate /*
97*0Sstevel@tonic-gate  * So is ctime...
98*0Sstevel@tonic-gate  */
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate /*
101*0Sstevel@tonic-gate  * This routine converts time as follows.
102*0Sstevel@tonic-gate  * The epoch is 0000 Jan 1 1970 GMT.
103*0Sstevel@tonic-gate  * The argument time is in seconds since then.
104*0Sstevel@tonic-gate  * The localtime(t) entry returns a pointer to an array
105*0Sstevel@tonic-gate  * containing
106*0Sstevel@tonic-gate  *  seconds (0-59)
107*0Sstevel@tonic-gate  *  minutes (0-59)
108*0Sstevel@tonic-gate  *  hours (0-23)
109*0Sstevel@tonic-gate  *  day of month (1-31)
110*0Sstevel@tonic-gate  *  month (0-11)
111*0Sstevel@tonic-gate  *  year-1970
112*0Sstevel@tonic-gate  *  weekday (0-6, Sun is 0)
113*0Sstevel@tonic-gate  *  day of the year
114*0Sstevel@tonic-gate  *  daylight savings flag
115*0Sstevel@tonic-gate  *
116*0Sstevel@tonic-gate  * The routine corrects for daylight saving
117*0Sstevel@tonic-gate  * time and will work in any time zone provided
118*0Sstevel@tonic-gate  * "timezone" is adjusted to the difference between
119*0Sstevel@tonic-gate  * Greenwich and local standard time (measured in seconds).
120*0Sstevel@tonic-gate  * In places like Michigan "daylight" must
121*0Sstevel@tonic-gate  * be initialized to 0 to prevent the conversion
122*0Sstevel@tonic-gate  * to daylight time.
123*0Sstevel@tonic-gate  * There is a table which accounts for the peculiarities
124*0Sstevel@tonic-gate  * undergone by daylight time in 1974-1975.
125*0Sstevel@tonic-gate  *
126*0Sstevel@tonic-gate  * The routine does not work
127*0Sstevel@tonic-gate  * in Saudi Arabia which runs on Solar time.
128*0Sstevel@tonic-gate  *
129*0Sstevel@tonic-gate  * asctime(tvec)
130*0Sstevel@tonic-gate  * where tvec is produced by localtime
131*0Sstevel@tonic-gate  * returns a ptr to a character string
132*0Sstevel@tonic-gate  * that has the ascii time in the form
133*0Sstevel@tonic-gate  *	Thu Jan 01 00:00:00 1970\n\0
134*0Sstevel@tonic-gate  *	01234567890123456789012345
135*0Sstevel@tonic-gate  *	0	  1	    2
136*0Sstevel@tonic-gate  *
137*0Sstevel@tonic-gate  * ctime(t) just calls localtime, then asctime.
138*0Sstevel@tonic-gate  *
139*0Sstevel@tonic-gate  * tzset() looks for an environment variable named
140*0Sstevel@tonic-gate  * TZ.
141*0Sstevel@tonic-gate  * If the variable is present, it will set the external
142*0Sstevel@tonic-gate  * variables "timezone", "altzone", "daylight", and "tzname"
143*0Sstevel@tonic-gate  * appropriately. It is called by localtime, and
144*0Sstevel@tonic-gate  * may also be called explicitly by the user.
145*0Sstevel@tonic-gate  */
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate 
148*0Sstevel@tonic-gate 
149*0Sstevel@tonic-gate #define	dysize(A) (((A)%4)? 365: 366)
150*0Sstevel@tonic-gate #define	CBUFSIZ 26
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate /*
153*0Sstevel@tonic-gate  * POSIX.1c standard version of the function asctime_r.
154*0Sstevel@tonic-gate  * User gets it via static asctime_r from the header file.
155*0Sstevel@tonic-gate  */
156*0Sstevel@tonic-gate char *
157*0Sstevel@tonic-gate __posix_asctime_r(const struct tm *t, char *cbuf)
158*0Sstevel@tonic-gate {
159*0Sstevel@tonic-gate 	const char *Date = "Day Mon 00 00:00:00 1900\n";
160*0Sstevel@tonic-gate 	const char *Day  = "SunMonTueWedThuFriSat";
161*0Sstevel@tonic-gate 	const char *Month = "JanFebMarAprMayJunJulAugSepOctNovDec";
162*0Sstevel@tonic-gate 	static char *ct_numb();
163*0Sstevel@tonic-gate 	const char *ncp;
164*0Sstevel@tonic-gate 	const int *tp;
165*0Sstevel@tonic-gate 	char *cp;
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate 	if (t == NULL)
168*0Sstevel@tonic-gate 		return (NULL);
169*0Sstevel@tonic-gate 
170*0Sstevel@tonic-gate 	cp = cbuf;
171*0Sstevel@tonic-gate 	for (ncp = Date; *cp++ = *ncp++; /* */);
172*0Sstevel@tonic-gate 	ncp = Day + (3*t->tm_wday);
173*0Sstevel@tonic-gate 	cp = cbuf;
174*0Sstevel@tonic-gate 	*cp++ = *ncp++;
175*0Sstevel@tonic-gate 	*cp++ = *ncp++;
176*0Sstevel@tonic-gate 	*cp++ = *ncp++;
177*0Sstevel@tonic-gate 	cp++;
178*0Sstevel@tonic-gate 	tp = &t->tm_mon;
179*0Sstevel@tonic-gate 	ncp = Month + ((*tp) * 3);
180*0Sstevel@tonic-gate 	*cp++ = *ncp++;
181*0Sstevel@tonic-gate 	*cp++ = *ncp++;
182*0Sstevel@tonic-gate 	*cp++ = *ncp++;
183*0Sstevel@tonic-gate 	cp = ct_numb(cp, *--tp);
184*0Sstevel@tonic-gate 	cp = ct_numb(cp, *--tp+100);
185*0Sstevel@tonic-gate 	cp = ct_numb(cp, *--tp+100);
186*0Sstevel@tonic-gate 	cp = ct_numb(cp, *--tp+100);
187*0Sstevel@tonic-gate 	if (t->tm_year > 9999) {
188*0Sstevel@tonic-gate 		errno = EOVERFLOW;
189*0Sstevel@tonic-gate 		return (NULL);
190*0Sstevel@tonic-gate 	} else {
191*0Sstevel@tonic-gate 		uint_t hun = 19 + (t->tm_year / 100);
192*0Sstevel@tonic-gate 		cp[1] = (hun / 10) + '0';
193*0Sstevel@tonic-gate 		cp[2] = (hun % 10) + '0';
194*0Sstevel@tonic-gate 	}
195*0Sstevel@tonic-gate 	cp += 2;
196*0Sstevel@tonic-gate 	cp = ct_numb(cp, t->tm_year+100);
197*0Sstevel@tonic-gate 	return (cbuf);
198*0Sstevel@tonic-gate }
199*0Sstevel@tonic-gate 
200*0Sstevel@tonic-gate /*
201*0Sstevel@tonic-gate  * POSIX.1c Draft-6 version of the function asctime_r.
202*0Sstevel@tonic-gate  * It was implemented by Solaris 2.3.
203*0Sstevel@tonic-gate  */
204*0Sstevel@tonic-gate char *
205*0Sstevel@tonic-gate _asctime_r(const struct tm *t, char *cbuf, int buflen)
206*0Sstevel@tonic-gate {
207*0Sstevel@tonic-gate 	if (buflen < CBUFSIZ) {
208*0Sstevel@tonic-gate 		errno = ERANGE;
209*0Sstevel@tonic-gate 		return (NULL);
210*0Sstevel@tonic-gate 	}
211*0Sstevel@tonic-gate 	return (__posix_asctime_r(t, cbuf));
212*0Sstevel@tonic-gate }
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate char *
215*0Sstevel@tonic-gate ctime(const time_t *t)
216*0Sstevel@tonic-gate {
217*0Sstevel@tonic-gate 	return (asctime(localtime(t)));
218*0Sstevel@tonic-gate }
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate char *
222*0Sstevel@tonic-gate asctime(const struct tm *t)
223*0Sstevel@tonic-gate {
224*0Sstevel@tonic-gate 	static char cbuf[CBUFSIZ];
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate 	return (_asctime_r(t, cbuf, CBUFSIZ));
227*0Sstevel@tonic-gate }
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate static char *
231*0Sstevel@tonic-gate ct_numb(char *cp, int n)
232*0Sstevel@tonic-gate {
233*0Sstevel@tonic-gate 	cp++;
234*0Sstevel@tonic-gate 	if (n >= 10)
235*0Sstevel@tonic-gate 		*cp++ = (n/10)%10 + '0';
236*0Sstevel@tonic-gate 	else
237*0Sstevel@tonic-gate 		*cp++ = ' ';		/* Pad with blanks */
238*0Sstevel@tonic-gate 	*cp++ = n%10 + '0';
239*0Sstevel@tonic-gate 	return (cp);
240*0Sstevel@tonic-gate }
241