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 GMT 1970n0
27 * 012345678901234567890123456789
28 * 0 1 2
29 *
30 * ctime(t) just calls localtime, then asctime.
31 */
32
33 #include <u.h>
34 #include <libc.h>
35
36 static char dmsize[12] =
37 {
38 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
39 };
40
41 /*
42 * The following table is used for 1974 and 1975 and
43 * gives the day number of the first day after the Sunday of the
44 * change.
45 */
46
47 static int dysize(int);
48 static void ct_numb(char*, int);
49
50 #define TZSIZE ((136*2)+10) /* 1970-2106; match tm2sec.c */
51
52 static void readtimezone(void);
53 static int rd_name(char**, char*);
54 static int rd_long(char**, long*);
55 static
56 struct
57 {
58 char stname[4];
59 char dlname[4];
60 long stdiff;
61 long dldiff;
62 ulong dlpairs[TZSIZE];
63 } timezone;
64
65 char*
ctime(long t)66 ctime(long t)
67 {
68 return asctime(localtime(t));
69 }
70
71 Tm*
localtime(long atim)72 localtime(long atim) /* should be ulong, but it's too late */
73 {
74 Tm *ct;
75 ulong tim, t, *p;
76 int dlflag;
77
78 tim = atim;
79 if(timezone.stname[0] == 0)
80 readtimezone();
81 t = tim + timezone.stdiff;
82 dlflag = 0;
83 for(p = timezone.dlpairs; *p; p += 2)
84 if(t >= p[0])
85 if(t < p[1]) {
86 t = tim + timezone.dldiff;
87 dlflag++;
88 break;
89 }
90 ct = gmtime(t);
91 if(dlflag){
92 strcpy(ct->zone, timezone.dlname);
93 ct->tzoff = timezone.dldiff;
94 } else {
95 strcpy(ct->zone, timezone.stname);
96 ct->tzoff = timezone.stdiff;
97 }
98 return ct;
99 }
100
101 Tm*
gmtime(long atim)102 gmtime(long atim) /* should be ulong, but it's too late */
103 {
104 int d0, d1;
105 long hms, day;
106 ulong tim;
107 static Tm xtime;
108
109 /*
110 * break initial number into days
111 */
112 tim = atim;
113 hms = tim % 86400L;
114 day = tim / 86400L;
115 if(hms < 0) {
116 hms += 86400L;
117 day -= 1;
118 }
119
120 /*
121 * generate hours:minutes:seconds
122 */
123 xtime.sec = hms % 60;
124 d1 = hms / 60;
125 xtime.min = d1 % 60;
126 d1 /= 60;
127 xtime.hour = d1;
128
129 /*
130 * day is the day number.
131 * generate day of the week.
132 * The addend is 4 mod 7 (1/1/1970 was Thursday)
133 */
134
135 xtime.wday = (day + 7340036L) % 7;
136
137 /*
138 * year number
139 */
140 if(day >= 0)
141 for(d1 = 1970; day >= dysize(d1); d1++)
142 day -= dysize(d1);
143 else
144 for (d1 = 1970; day < 0; d1--)
145 day += dysize(d1-1);
146 xtime.year = d1-1900;
147 xtime.yday = d0 = day;
148
149 /*
150 * generate month
151 */
152
153 if(dysize(d1) == 366)
154 dmsize[1] = 29;
155 for(d1 = 0; d0 >= dmsize[d1]; d1++)
156 d0 -= dmsize[d1];
157 dmsize[1] = 28;
158 xtime.mday = d0 + 1;
159 xtime.mon = d1;
160 strcpy(xtime.zone, "GMT");
161 return &xtime;
162 }
163
164 char*
asctime(Tm * t)165 asctime(Tm *t)
166 {
167 char *ncp;
168 static char cbuf[30];
169
170 strcpy(cbuf, "Thu Jan 01 00:00:00 GMT 1970\n");
171 ncp = &"SunMonTueWedThuFriSat"[t->wday*3];
172 cbuf[0] = *ncp++;
173 cbuf[1] = *ncp++;
174 cbuf[2] = *ncp;
175 ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[t->mon*3];
176 cbuf[4] = *ncp++;
177 cbuf[5] = *ncp++;
178 cbuf[6] = *ncp;
179 ct_numb(cbuf+8, t->mday);
180 ct_numb(cbuf+11, t->hour+100);
181 ct_numb(cbuf+14, t->min+100);
182 ct_numb(cbuf+17, t->sec+100);
183 ncp = t->zone;
184 cbuf[20] = *ncp++;
185 cbuf[21] = *ncp++;
186 cbuf[22] = *ncp;
187 if(t->year >= 100) {
188 cbuf[24] = '2';
189 cbuf[25] = '0';
190 }
191 ct_numb(cbuf+26, t->year+100);
192 return cbuf;
193 }
194
195 static
dysize(int y)196 dysize(int y)
197 {
198
199 if(y%4 == 0 && (y%100 != 0 || y%400 == 0))
200 return 366;
201 return 365;
202 }
203
204 static
205 void
ct_numb(char * cp,int n)206 ct_numb(char *cp, int n)
207 {
208
209 cp[0] = ' ';
210 if(n >= 10)
211 cp[0] = (n/10)%10 + '0';
212 cp[1] = n%10 + '0';
213 }
214
215 static
216 void
readtimezone(void)217 readtimezone(void)
218 {
219 char buf[TZSIZE*11+30], *p;
220 int i;
221
222 memset(buf, 0, sizeof(buf));
223 i = open("/env/timezone", 0);
224 if(i < 0)
225 goto error;
226 if(read(i, buf, sizeof(buf)) >= sizeof(buf)){
227 close(i);
228 goto error;
229 }
230 close(i);
231 p = buf;
232 if(rd_name(&p, timezone.stname))
233 goto error;
234 if(rd_long(&p, &timezone.stdiff))
235 goto error;
236 if(rd_name(&p, timezone.dlname))
237 goto error;
238 if(rd_long(&p, &timezone.dldiff))
239 goto error;
240 for(i=0; i<TZSIZE; i++) {
241 if(rd_long(&p, (long *)&timezone.dlpairs[i]))
242 goto error;
243 if(timezone.dlpairs[i] == 0)
244 return;
245 }
246 /* array too small for input */
247 error:
248 timezone.stdiff = 0;
249 strcpy(timezone.stname, "GMT");
250 timezone.dlpairs[0] = 0;
251 }
252
253 static
rd_name(char ** f,char * p)254 rd_name(char **f, char *p)
255 {
256 int c, i;
257
258 for(;;) {
259 c = *(*f)++;
260 if(c != ' ' && c != '\n')
261 break;
262 }
263 for(i=0; i<3; i++) {
264 if(c == ' ' || c == '\n')
265 return 1;
266 *p++ = c;
267 c = *(*f)++;
268 }
269 if(c != ' ' && c != '\n')
270 return 1;
271 *p = 0;
272 return 0;
273 }
274
275 static
rd_long(char ** f,long * p)276 rd_long(char **f, long *p)
277 {
278 int c, s;
279 long l;
280
281 s = 0;
282 for(;;) {
283 c = *(*f)++;
284 if(c == '-') {
285 s++;
286 continue;
287 }
288 if(c != ' ' && c != '\n')
289 break;
290 }
291 if(c == 0) {
292 *p = 0;
293 return 0;
294 }
295 l = 0;
296 for(;;) {
297 if(c == ' ' || c == '\n')
298 break;
299 if(c < '0' || c > '9')
300 return 1;
301 l = l*10 + c-'0';
302 c = *(*f)++;
303 }
304 if(s)
305 l = -l;
306 *p = l;
307 return 0;
308 }
309