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