xref: /plan9-contrib/sys/src/ape/lib/ap/plan9/ctime.c (revision 246175410ecf4ee584669678eabdce6c935e3dd4)
13e12c5d1SDavid du Colombier /*
23e12c5d1SDavid du Colombier  * This routine converts time as follows.
33e12c5d1SDavid du Colombier  * The epoch is 0000 Jan 1 1970 GMT.
43e12c5d1SDavid du Colombier  * The argument time is in seconds since then.
53e12c5d1SDavid du Colombier  * The localtime(t) entry returns a pointer to an array
63e12c5d1SDavid du Colombier  * containing
73e12c5d1SDavid du Colombier  *
83e12c5d1SDavid du Colombier  *	seconds (0-59)
93e12c5d1SDavid du Colombier  *	minutes (0-59)
103e12c5d1SDavid du Colombier  *	hours (0-23)
113e12c5d1SDavid du Colombier  *	day of month (1-31)
123e12c5d1SDavid du Colombier  *	month (0-11)
133e12c5d1SDavid du Colombier  *	year-1970
143e12c5d1SDavid du Colombier  *	weekday (0-6, Sun is 0)
153e12c5d1SDavid du Colombier  *	day of the year
163e12c5d1SDavid du Colombier  *	daylight savings flag
173e12c5d1SDavid du Colombier  *
183e12c5d1SDavid du Colombier  * The routine gets the daylight savings time from the environment.
193e12c5d1SDavid du Colombier  *
203e12c5d1SDavid du Colombier  * asctime(tvec))
213e12c5d1SDavid du Colombier  * where tvec is produced by localtime
223e12c5d1SDavid du Colombier  * returns a ptr to a character string
233e12c5d1SDavid du Colombier  * that has the ascii time in the form
243e12c5d1SDavid du Colombier  *
253e12c5d1SDavid du Colombier  *	                            \\
263e12c5d1SDavid du Colombier  *	Thu Jan 01 00:00:00 1970n0
273e12c5d1SDavid du Colombier  *	01234567890123456789012345
283e12c5d1SDavid du Colombier  *	0	  1	    2
293e12c5d1SDavid du Colombier  *
303e12c5d1SDavid du Colombier  * ctime(t) just calls localtime, then asctime.
313e12c5d1SDavid du Colombier  */
323e12c5d1SDavid du Colombier 
333e12c5d1SDavid du Colombier #include <sys/types.h>
343e12c5d1SDavid du Colombier #include <sys/stat.h>
353e12c5d1SDavid du Colombier #include <fcntl.h>
363e12c5d1SDavid du Colombier #include <time.h>
373e12c5d1SDavid du Colombier #include <unistd.h>
383e12c5d1SDavid du Colombier #include <string.h>
393e12c5d1SDavid du Colombier 
403e12c5d1SDavid du Colombier static	char	dmsize[12] =
413e12c5d1SDavid du Colombier {
423e12c5d1SDavid du Colombier 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
433e12c5d1SDavid du Colombier };
443e12c5d1SDavid du Colombier 
453e12c5d1SDavid du Colombier /*
463e12c5d1SDavid du Colombier  * The following table is used for 1974 and 1975 and
473e12c5d1SDavid du Colombier  * gives the day number of the first day after the Sunday of the
483e12c5d1SDavid du Colombier  * change.
493e12c5d1SDavid du Colombier  */
503e12c5d1SDavid du Colombier 
513e12c5d1SDavid du Colombier static	int	dysize(int);
523e12c5d1SDavid du Colombier static	void	ct_numb(char*, int);
533e12c5d1SDavid du Colombier static	void	readtimezone(void);
543e12c5d1SDavid du Colombier static	int	rd_name(char**, char*);
553e12c5d1SDavid du Colombier static	int	rd_long(char**, long*);
562d069feaSDavid du Colombier 
572d069feaSDavid du Colombier #define	TZSIZE	150
582d069feaSDavid du Colombier 
593e12c5d1SDavid du Colombier static
603e12c5d1SDavid du Colombier struct
613e12c5d1SDavid du Colombier {
623e12c5d1SDavid du Colombier 	char	stname[4];
633e12c5d1SDavid du Colombier 	char	dlname[4];
643e12c5d1SDavid du Colombier 	long	stdiff;
653e12c5d1SDavid du Colombier 	long	dldiff;
663e12c5d1SDavid du Colombier 	long	dlpairs[TZSIZE];
673e12c5d1SDavid du Colombier } timezone;
683e12c5d1SDavid du Colombier 
693e12c5d1SDavid du Colombier char*
ctime(const time_t * t)703e12c5d1SDavid du Colombier ctime(const time_t *t)
713e12c5d1SDavid du Colombier {
723e12c5d1SDavid du Colombier 	return asctime(localtime(t));
733e12c5d1SDavid du Colombier }
743e12c5d1SDavid du Colombier 
753e12c5d1SDavid du Colombier struct tm*
gmtime_r(const time_t * timp,struct tm * result)762d069feaSDavid du Colombier gmtime_r(const time_t *timp, struct tm *result)
772d069feaSDavid du Colombier {
782d069feaSDavid du Colombier 	int d0, d1;
792d069feaSDavid du Colombier 	long hms, day;
802d069feaSDavid du Colombier 	time_t tim;
812d069feaSDavid du Colombier 
822d069feaSDavid du Colombier 	tim = *timp;
832d069feaSDavid du Colombier 	/*
842d069feaSDavid du Colombier 	 * break initial number into days
852d069feaSDavid du Colombier 	 */
862d069feaSDavid du Colombier 	hms = tim % 86400L;
872d069feaSDavid du Colombier 	day = tim / 86400L;
882d069feaSDavid du Colombier 	if(hms < 0) {
892d069feaSDavid du Colombier 		hms += 86400L;
902d069feaSDavid du Colombier 		day -= 1;
912d069feaSDavid du Colombier 	}
922d069feaSDavid du Colombier 
932d069feaSDavid du Colombier 	/*
942d069feaSDavid du Colombier 	 * generate hours:minutes:seconds
952d069feaSDavid du Colombier 	 */
962d069feaSDavid du Colombier 	result->tm_sec = hms % 60;
972d069feaSDavid du Colombier 	d1 = hms / 60;
982d069feaSDavid du Colombier 	result->tm_min = d1 % 60;
992d069feaSDavid du Colombier 	d1 /= 60;
1002d069feaSDavid du Colombier 	result->tm_hour = d1;
1012d069feaSDavid du Colombier 
1022d069feaSDavid du Colombier 	/*
1032d069feaSDavid du Colombier 	 * day is the day number.
1042d069feaSDavid du Colombier 	 * generate day of the week.
1052d069feaSDavid du Colombier 	 * The addend is 4 mod 7 (1/1/1970 was Thursday)
1062d069feaSDavid du Colombier 	 */
1072d069feaSDavid du Colombier 
1082d069feaSDavid du Colombier 	result->tm_wday = (day + 7340036L) % 7;
1092d069feaSDavid du Colombier 
1102d069feaSDavid du Colombier 	/*
1112d069feaSDavid du Colombier 	 * year number
1122d069feaSDavid du Colombier 	 */
1132d069feaSDavid du Colombier 	if(day >= 0)
1142d069feaSDavid du Colombier 		for(d1 = 70; day >= dysize(d1); d1++)
1152d069feaSDavid du Colombier 			day -= dysize(d1);
1162d069feaSDavid du Colombier 	else
1172d069feaSDavid du Colombier 		for (d1 = 70; day < 0; d1--)
1182d069feaSDavid du Colombier 			day += dysize(d1-1);
1192d069feaSDavid du Colombier 	result->tm_year = d1;
1202d069feaSDavid du Colombier 	result->tm_yday = d0 = day;
1212d069feaSDavid du Colombier 
1222d069feaSDavid du Colombier 	/*
1232d069feaSDavid du Colombier 	 * generate month
1242d069feaSDavid du Colombier 	 */
1252d069feaSDavid du Colombier 
1262d069feaSDavid du Colombier 	if(dysize(d1) == 366)
1272d069feaSDavid du Colombier 		dmsize[1] = 29;
1282d069feaSDavid du Colombier 	for(d1 = 0; d0 >= dmsize[d1]; d1++)
1292d069feaSDavid du Colombier 		d0 -= dmsize[d1];
1302d069feaSDavid du Colombier 	dmsize[1] = 28;
1312d069feaSDavid du Colombier 	result->tm_mday = d0 + 1;
1322d069feaSDavid du Colombier 	result->tm_mon = d1;
1332d069feaSDavid du Colombier 	result->tm_isdst = 0;
1342d069feaSDavid du Colombier 	return result;
1352d069feaSDavid du Colombier }
1362d069feaSDavid du Colombier 
1372d069feaSDavid du Colombier struct tm*
gmtime(const time_t * timp)1382d069feaSDavid du Colombier gmtime(const time_t *timp)
1392d069feaSDavid du Colombier {
1402d069feaSDavid du Colombier 	static struct tm xtime;
1412d069feaSDavid du Colombier 
1422d069feaSDavid du Colombier 	return gmtime_r(timp, &xtime);
1432d069feaSDavid du Colombier }
1442d069feaSDavid du Colombier 
1452d069feaSDavid du Colombier struct tm*
localtime_r(const time_t * timp,struct tm * result)1462d069feaSDavid du Colombier localtime_r(const time_t *timp, struct tm *result)
1473e12c5d1SDavid du Colombier {
1483e12c5d1SDavid du Colombier 	struct tm *ct;
1493e12c5d1SDavid du Colombier 	time_t t, tim;
1503e12c5d1SDavid du Colombier 	long *p;
151781103c4SDavid du Colombier 	int dlflag;
1523e12c5d1SDavid du Colombier 
1533e12c5d1SDavid du Colombier 	tim = *timp;
1543e12c5d1SDavid du Colombier 	if(timezone.stname[0] == 0)
1553e12c5d1SDavid du Colombier 		readtimezone();
1563e12c5d1SDavid du Colombier 	t = tim + timezone.stdiff;
1573e12c5d1SDavid du Colombier 	dlflag = 0;
1583e12c5d1SDavid du Colombier 	for(p = timezone.dlpairs; *p; p += 2)
1593e12c5d1SDavid du Colombier 		if(t >= p[0])
1603e12c5d1SDavid du Colombier 		if(t < p[1]) {
1613e12c5d1SDavid du Colombier 			t = tim + timezone.dldiff;
1623e12c5d1SDavid du Colombier 			dlflag++;
1633e12c5d1SDavid du Colombier 			break;
1643e12c5d1SDavid du Colombier 		}
1652d069feaSDavid du Colombier 	ct = gmtime_r(&t, result);
1663e12c5d1SDavid du Colombier 	ct->tm_isdst = dlflag;
1673e12c5d1SDavid du Colombier 	return ct;
1683e12c5d1SDavid du Colombier }
1693e12c5d1SDavid du Colombier 
1703e12c5d1SDavid du Colombier struct tm*
localtime(const time_t * timp)1712d069feaSDavid du Colombier localtime(const time_t *timp)
1723e12c5d1SDavid du Colombier {
1733e12c5d1SDavid du Colombier 	static struct tm xtime;
1743e12c5d1SDavid du Colombier 
1752d069feaSDavid du Colombier 	return localtime_r(timp, &xtime);
1763e12c5d1SDavid du Colombier }
1773e12c5d1SDavid du Colombier 
1782d069feaSDavid du Colombier char*
asctime_r(const struct tm * t,char * buf)1792d069feaSDavid du Colombier asctime_r(const struct tm *t, char *buf)
1802d069feaSDavid du Colombier {
1812d069feaSDavid du Colombier 	char *ncp;
1823e12c5d1SDavid du Colombier 
1832d069feaSDavid du Colombier 	strcpy(buf, "Thu Jan 01 00:00:00 1970\n");
1842d069feaSDavid du Colombier 	ncp = &"SunMonTueWedThuFriSat"[t->tm_wday*3];
1852d069feaSDavid du Colombier 	buf[0] = *ncp++;
1862d069feaSDavid du Colombier 	buf[1] = *ncp++;
1872d069feaSDavid du Colombier 	buf[2] = *ncp;
1882d069feaSDavid du Colombier 	ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[t->tm_mon*3];
1892d069feaSDavid du Colombier 	buf[4] = *ncp++;
1902d069feaSDavid du Colombier 	buf[5] = *ncp++;
1912d069feaSDavid du Colombier 	buf[6] = *ncp;
1922d069feaSDavid du Colombier 	ct_numb(buf+8, t->tm_mday);
1932d069feaSDavid du Colombier 	ct_numb(buf+11, t->tm_hour+100);
1942d069feaSDavid du Colombier 	ct_numb(buf+14, t->tm_min+100);
1952d069feaSDavid du Colombier 	ct_numb(buf+17, t->tm_sec+100);
1962d069feaSDavid du Colombier 	if(t->tm_year >= 100) {
1972d069feaSDavid du Colombier 		buf[20] = '2';
198*24617541SDavid du Colombier 		buf[21] = t->tm_year >= 200? '1': '0';
1992d069feaSDavid du Colombier 	}
2002d069feaSDavid du Colombier 	ct_numb(buf+22, t->tm_year+100);
2012d069feaSDavid du Colombier 	return buf;
2023e12c5d1SDavid du Colombier }
2033e12c5d1SDavid du Colombier 
2043e12c5d1SDavid du Colombier char*
asctime(const struct tm * t)2053e12c5d1SDavid du Colombier asctime(const struct tm *t)
2063e12c5d1SDavid du Colombier {
2073e12c5d1SDavid du Colombier 	static char cbuf[30];
2083e12c5d1SDavid du Colombier 
2092d069feaSDavid du Colombier 	return asctime_r(t, cbuf);
2103e12c5d1SDavid du Colombier }
2113e12c5d1SDavid du Colombier 
2123e12c5d1SDavid du Colombier static
dysize(int y)2133e12c5d1SDavid du Colombier dysize(int y)
2143e12c5d1SDavid du Colombier {
2153e12c5d1SDavid du Colombier 	if((y%4) == 0)
2163e12c5d1SDavid du Colombier 		return 366;
2173e12c5d1SDavid du Colombier 	return 365;
2183e12c5d1SDavid du Colombier }
2193e12c5d1SDavid du Colombier 
2203e12c5d1SDavid du Colombier static
2213e12c5d1SDavid du Colombier void
ct_numb(char * cp,int n)2223e12c5d1SDavid du Colombier ct_numb(char *cp, int n)
2233e12c5d1SDavid du Colombier {
2243e12c5d1SDavid du Colombier 	cp[0] = ' ';
2253e12c5d1SDavid du Colombier 	if(n >= 10)
2263e12c5d1SDavid du Colombier 		cp[0] = (n/10)%10 + '0';
2273e12c5d1SDavid du Colombier 	cp[1] = n%10 + '0';
2283e12c5d1SDavid du Colombier }
2293e12c5d1SDavid du Colombier 
2303e12c5d1SDavid du Colombier static
2313e12c5d1SDavid du Colombier void
readtimezone(void)2323e12c5d1SDavid du Colombier readtimezone(void)
2333e12c5d1SDavid du Colombier {
2343e12c5d1SDavid du Colombier 	char buf[TZSIZE*11+30], *p;
2353e12c5d1SDavid du Colombier 	int i;
2363e12c5d1SDavid du Colombier 
2373e12c5d1SDavid du Colombier 	memset(buf, 0, sizeof(buf));
2383e12c5d1SDavid du Colombier 	i = open("/env/timezone", 0);
2393e12c5d1SDavid du Colombier 	if(i < 0)
2403e12c5d1SDavid du Colombier 		goto error;
2413e12c5d1SDavid du Colombier 	if(read(i, buf, sizeof(buf)) >= sizeof(buf))
2423e12c5d1SDavid du Colombier 		goto error;
2433e12c5d1SDavid du Colombier 	close(i);
2443e12c5d1SDavid du Colombier 	p = buf;
2453e12c5d1SDavid du Colombier 	if(rd_name(&p, timezone.stname))
2463e12c5d1SDavid du Colombier 		goto error;
2473e12c5d1SDavid du Colombier 	if(rd_long(&p, &timezone.stdiff))
2483e12c5d1SDavid du Colombier 		goto error;
2493e12c5d1SDavid du Colombier 	if(rd_name(&p, timezone.dlname))
2503e12c5d1SDavid du Colombier 		goto error;
2513e12c5d1SDavid du Colombier 	if(rd_long(&p, &timezone.dldiff))
2523e12c5d1SDavid du Colombier 		goto error;
2533e12c5d1SDavid du Colombier 	for(i=0; i<TZSIZE; i++) {
2543e12c5d1SDavid du Colombier 		if(rd_long(&p, &timezone.dlpairs[i]))
2553e12c5d1SDavid du Colombier 			goto error;
2563e12c5d1SDavid du Colombier 		if(timezone.dlpairs[i] == 0)
2573e12c5d1SDavid du Colombier 			return;
2583e12c5d1SDavid du Colombier 	}
2593e12c5d1SDavid du Colombier 
2603e12c5d1SDavid du Colombier error:
2613e12c5d1SDavid du Colombier 	timezone.stdiff = 0;
2623e12c5d1SDavid du Colombier 	strcpy(timezone.stname, "GMT");
2633e12c5d1SDavid du Colombier 	timezone.dlpairs[0] = 0;
2643e12c5d1SDavid du Colombier }
2653e12c5d1SDavid du Colombier 
2663e12c5d1SDavid du Colombier static
rd_name(char ** f,char * p)2673e12c5d1SDavid du Colombier rd_name(char **f, char *p)
2683e12c5d1SDavid du Colombier {
2693e12c5d1SDavid du Colombier 	int c, i;
2703e12c5d1SDavid du Colombier 
2713e12c5d1SDavid du Colombier 	for(;;) {
2723e12c5d1SDavid du Colombier 		c = *(*f)++;
2733e12c5d1SDavid du Colombier 		if(c != ' ' && c != '\n')
2743e12c5d1SDavid du Colombier 			break;
2753e12c5d1SDavid du Colombier 	}
2763e12c5d1SDavid du Colombier 	for(i=0; i<3; i++) {
2773e12c5d1SDavid du Colombier 		if(c == ' ' || c == '\n')
2783e12c5d1SDavid du Colombier 			return 1;
2793e12c5d1SDavid du Colombier 		*p++ = c;
2803e12c5d1SDavid du Colombier 		c = *(*f)++;
2813e12c5d1SDavid du Colombier 	}
2823e12c5d1SDavid du Colombier 	if(c != ' ' && c != '\n')
2833e12c5d1SDavid du Colombier 		return 1;
2843e12c5d1SDavid du Colombier 	*p = 0;
2853e12c5d1SDavid du Colombier 	return 0;
2863e12c5d1SDavid du Colombier }
2873e12c5d1SDavid du Colombier 
2883e12c5d1SDavid du Colombier static
rd_long(char ** f,long * p)2893e12c5d1SDavid du Colombier rd_long(char **f, long *p)
2903e12c5d1SDavid du Colombier {
2913e12c5d1SDavid du Colombier 	int c, s;
2923e12c5d1SDavid du Colombier 	long l;
2933e12c5d1SDavid du Colombier 
2943e12c5d1SDavid du Colombier 	s = 0;
2953e12c5d1SDavid du Colombier 	for(;;) {
2963e12c5d1SDavid du Colombier 		c = *(*f)++;
2973e12c5d1SDavid du Colombier 		if(c == '-') {
2983e12c5d1SDavid du Colombier 			s++;
2993e12c5d1SDavid du Colombier 			continue;
3003e12c5d1SDavid du Colombier 		}
3013e12c5d1SDavid du Colombier 		if(c != ' ' && c != '\n')
3023e12c5d1SDavid du Colombier 			break;
3033e12c5d1SDavid du Colombier 	}
3043e12c5d1SDavid du Colombier 	if(c == 0) {
3053e12c5d1SDavid du Colombier 		*p = 0;
3063e12c5d1SDavid du Colombier 		return 0;
3073e12c5d1SDavid du Colombier 	}
3083e12c5d1SDavid du Colombier 	l = 0;
3093e12c5d1SDavid du Colombier 	for(;;) {
3103e12c5d1SDavid du Colombier 		if(c == ' ' || c == '\n')
3113e12c5d1SDavid du Colombier 			break;
3123e12c5d1SDavid du Colombier 		if(c < '0' || c > '9')
3133e12c5d1SDavid du Colombier 			return 1;
3143e12c5d1SDavid du Colombier 		l = l*10 + c-'0';
3153e12c5d1SDavid du Colombier 		c = *(*f)++;
3163e12c5d1SDavid du Colombier 	}
3173e12c5d1SDavid du Colombier 	if(s)
3183e12c5d1SDavid du Colombier 		l = -l;
3193e12c5d1SDavid du Colombier 	*p = l;
3203e12c5d1SDavid du Colombier 	return 0;
3213e12c5d1SDavid du Colombier }
322