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