1 /*
2 * This routine converts time as follows.
3 * The epoch is 0000 Jan 1 1970 GMT.
4 * The argument time is in seconds since then.
5 * The localtime(t) entry returns a pointer to an array
6 * containing
7 *
8 * seconds (0-59)
9 * minutes (0-59)
10 * hours (0-23)
11 * day of month (1-31)
12 * month (0-11)
13 * year-1970
14 * weekday (0-6, Sun is 0)
15 * day of the year
16 * daylight savings flag
17 *
18 * The routine gets the daylight savings time from the environment.
19 *
20 * asctime(tvec))
21 * where tvec is produced by localtime
22 * returns a ptr to a character string
23 * that has the ascii time in the form
24 *
25 * \\
26 * Thu Jan 01 00:00:00 1970n0
27 * 01234567890123456789012345
28 * 0 1 2
29 *
30 * ctime(t) just calls localtime, then asctime.
31 */
32
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #include <time.h>
37 #include <unistd.h>
38 #include <string.h>
39
40 static char dmsize[12] =
41 {
42 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
43 };
44
45 /*
46 * The following table is used for 1974 and 1975 and
47 * gives the day number of the first day after the Sunday of the
48 * change.
49 */
50
51 static int dysize(int);
52 static void ct_numb(char*, int);
53 static void readtimezone(void);
54 static int rd_name(char**, char*);
55 static int rd_long(char**, long*);
56
57 #define TZSIZE 150
58
59 static
60 struct
61 {
62 char stname[4];
63 char dlname[4];
64 long stdiff;
65 long dldiff;
66 long dlpairs[TZSIZE];
67 } timezone;
68
69 char*
ctime(const time_t * t)70 ctime(const time_t *t)
71 {
72 return asctime(localtime(t));
73 }
74
75 struct tm*
gmtime_r(const time_t * timp,struct tm * result)76 gmtime_r(const time_t *timp, struct tm *result)
77 {
78 int d0, d1;
79 long hms, day;
80 time_t tim;
81
82 tim = *timp;
83 /*
84 * break initial number into days
85 */
86 hms = tim % 86400L;
87 day = tim / 86400L;
88 if(hms < 0) {
89 hms += 86400L;
90 day -= 1;
91 }
92
93 /*
94 * generate hours:minutes:seconds
95 */
96 result->tm_sec = hms % 60;
97 d1 = hms / 60;
98 result->tm_min = d1 % 60;
99 d1 /= 60;
100 result->tm_hour = d1;
101
102 /*
103 * day is the day number.
104 * generate day of the week.
105 * The addend is 4 mod 7 (1/1/1970 was Thursday)
106 */
107
108 result->tm_wday = (day + 7340036L) % 7;
109
110 /*
111 * year number
112 */
113 if(day >= 0)
114 for(d1 = 70; day >= dysize(d1); d1++)
115 day -= dysize(d1);
116 else
117 for (d1 = 70; day < 0; d1--)
118 day += dysize(d1-1);
119 result->tm_year = d1;
120 result->tm_yday = d0 = day;
121
122 /*
123 * generate month
124 */
125
126 if(dysize(d1) == 366)
127 dmsize[1] = 29;
128 for(d1 = 0; d0 >= dmsize[d1]; d1++)
129 d0 -= dmsize[d1];
130 dmsize[1] = 28;
131 result->tm_mday = d0 + 1;
132 result->tm_mon = d1;
133 result->tm_isdst = 0;
134 return result;
135 }
136
137 struct tm*
gmtime(const time_t * timp)138 gmtime(const time_t *timp)
139 {
140 static struct tm xtime;
141
142 return gmtime_r(timp, &xtime);
143 }
144
145 struct tm*
localtime_r(const time_t * timp,struct tm * result)146 localtime_r(const time_t *timp, struct tm *result)
147 {
148 struct tm *ct;
149 time_t t, tim;
150 long *p;
151 int dlflag;
152
153 tim = *timp;
154 if(timezone.stname[0] == 0)
155 readtimezone();
156 t = tim + timezone.stdiff;
157 dlflag = 0;
158 for(p = timezone.dlpairs; *p; p += 2)
159 if(t >= p[0])
160 if(t < p[1]) {
161 t = tim + timezone.dldiff;
162 dlflag++;
163 break;
164 }
165 ct = gmtime_r(&t, result);
166 ct->tm_isdst = dlflag;
167 return ct;
168 }
169
170 struct tm*
localtime(const time_t * timp)171 localtime(const time_t *timp)
172 {
173 static struct tm xtime;
174
175 return localtime_r(timp, &xtime);
176 }
177
178 char*
asctime_r(const struct tm * t,char * buf)179 asctime_r(const struct tm *t, char *buf)
180 {
181 char *ncp;
182
183 strcpy(buf, "Thu Jan 01 00:00:00 1970\n");
184 ncp = &"SunMonTueWedThuFriSat"[t->tm_wday*3];
185 buf[0] = *ncp++;
186 buf[1] = *ncp++;
187 buf[2] = *ncp;
188 ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[t->tm_mon*3];
189 buf[4] = *ncp++;
190 buf[5] = *ncp++;
191 buf[6] = *ncp;
192 ct_numb(buf+8, t->tm_mday);
193 ct_numb(buf+11, t->tm_hour+100);
194 ct_numb(buf+14, t->tm_min+100);
195 ct_numb(buf+17, t->tm_sec+100);
196 if(t->tm_year >= 100) {
197 buf[20] = '2';
198 buf[21] = t->tm_year >= 200? '1': '0';
199 }
200 ct_numb(buf+22, t->tm_year+100);
201 return buf;
202 }
203
204 char*
asctime(const struct tm * t)205 asctime(const struct tm *t)
206 {
207 static char cbuf[30];
208
209 return asctime_r(t, cbuf);
210 }
211
212 static
dysize(int y)213 dysize(int y)
214 {
215 if((y%4) == 0)
216 return 366;
217 return 365;
218 }
219
220 static
221 void
ct_numb(char * cp,int n)222 ct_numb(char *cp, int n)
223 {
224 cp[0] = ' ';
225 if(n >= 10)
226 cp[0] = (n/10)%10 + '0';
227 cp[1] = n%10 + '0';
228 }
229
230 static
231 void
readtimezone(void)232 readtimezone(void)
233 {
234 char buf[TZSIZE*11+30], *p;
235 int i;
236
237 memset(buf, 0, sizeof(buf));
238 i = open("/env/timezone", 0);
239 if(i < 0)
240 goto error;
241 if(read(i, buf, sizeof(buf)) >= sizeof(buf))
242 goto error;
243 close(i);
244 p = buf;
245 if(rd_name(&p, timezone.stname))
246 goto error;
247 if(rd_long(&p, &timezone.stdiff))
248 goto error;
249 if(rd_name(&p, timezone.dlname))
250 goto error;
251 if(rd_long(&p, &timezone.dldiff))
252 goto error;
253 for(i=0; i<TZSIZE; i++) {
254 if(rd_long(&p, &timezone.dlpairs[i]))
255 goto error;
256 if(timezone.dlpairs[i] == 0)
257 return;
258 }
259
260 error:
261 timezone.stdiff = 0;
262 strcpy(timezone.stname, "GMT");
263 timezone.dlpairs[0] = 0;
264 }
265
266 static
rd_name(char ** f,char * p)267 rd_name(char **f, char *p)
268 {
269 int c, i;
270
271 for(;;) {
272 c = *(*f)++;
273 if(c != ' ' && c != '\n')
274 break;
275 }
276 for(i=0; i<3; i++) {
277 if(c == ' ' || c == '\n')
278 return 1;
279 *p++ = c;
280 c = *(*f)++;
281 }
282 if(c != ' ' && c != '\n')
283 return 1;
284 *p = 0;
285 return 0;
286 }
287
288 static
rd_long(char ** f,long * p)289 rd_long(char **f, long *p)
290 {
291 int c, s;
292 long l;
293
294 s = 0;
295 for(;;) {
296 c = *(*f)++;
297 if(c == '-') {
298 s++;
299 continue;
300 }
301 if(c != ' ' && c != '\n')
302 break;
303 }
304 if(c == 0) {
305 *p = 0;
306 return 0;
307 }
308 l = 0;
309 for(;;) {
310 if(c == ' ' || c == '\n')
311 break;
312 if(c < '0' || c > '9')
313 return 1;
314 l = l*10 + c-'0';
315 c = *(*f)++;
316 }
317 if(s)
318 l = -l;
319 *p = l;
320 return 0;
321 }
322