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