xref: /plan9-contrib/sys/src/ape/lib/ap/plan9/ctime.c (revision 246175410ecf4ee584669678eabdce6c935e3dd4)
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