xref: /plan9-contrib/sys/src/libc/9sys/ctime.c (revision 54dec0678461a9d7af09e995e96ae173d1daa5c7)
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 GMT 1970n0
273e12c5d1SDavid du Colombier  *	012345678901234567890123456789
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 <u.h>
343e12c5d1SDavid du Colombier #include <libc.h>
353e12c5d1SDavid du Colombier 
363e12c5d1SDavid du Colombier static	char	dmsize[12] =
373e12c5d1SDavid du Colombier {
383e12c5d1SDavid du Colombier 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
393e12c5d1SDavid du Colombier };
403e12c5d1SDavid du Colombier 
413e12c5d1SDavid du Colombier /*
423e12c5d1SDavid du Colombier  * The following table is used for 1974 and 1975 and
433e12c5d1SDavid du Colombier  * gives the day number of the first day after the Sunday of the
443e12c5d1SDavid du Colombier  * change.
453e12c5d1SDavid du Colombier  */
463e12c5d1SDavid du Colombier 
473e12c5d1SDavid du Colombier static	int	dysize(int);
483e12c5d1SDavid du Colombier static	void	ct_numb(char*, int);
493e12c5d1SDavid du Colombier 
50*54dec067SDavid du Colombier #define	TZSIZE	((136*2)+10)		/* 1970-2106; match tm2sec.c */
51*54dec067SDavid du Colombier 
523e12c5d1SDavid du Colombier static	void	readtimezone(void);
533e12c5d1SDavid du Colombier static	int	rd_name(char**, char*);
543e12c5d1SDavid du Colombier static	int	rd_long(char**, long*);
553e12c5d1SDavid du Colombier static
563e12c5d1SDavid du Colombier struct
573e12c5d1SDavid du Colombier {
583e12c5d1SDavid du Colombier 	char	stname[4];
593e12c5d1SDavid du Colombier 	char	dlname[4];
603e12c5d1SDavid du Colombier 	long	stdiff;
613e12c5d1SDavid du Colombier 	long	dldiff;
62*54dec067SDavid du Colombier 	ulong	dlpairs[TZSIZE];
633e12c5d1SDavid du Colombier } timezone;
643e12c5d1SDavid du Colombier 
653e12c5d1SDavid du Colombier char*
ctime(long t)663e12c5d1SDavid du Colombier ctime(long t)
673e12c5d1SDavid du Colombier {
683e12c5d1SDavid du Colombier 	return asctime(localtime(t));
693e12c5d1SDavid du Colombier }
703e12c5d1SDavid du Colombier 
713e12c5d1SDavid du Colombier Tm*
localtime(long atim)72*54dec067SDavid du Colombier localtime(long atim)		/* should be ulong, but it's too late */
733e12c5d1SDavid du Colombier {
743e12c5d1SDavid du Colombier 	Tm *ct;
75*54dec067SDavid du Colombier 	ulong tim, t, *p;
763e12c5d1SDavid du Colombier 	int dlflag;
773e12c5d1SDavid du Colombier 
78*54dec067SDavid du Colombier 	tim = atim;
793e12c5d1SDavid du Colombier 	if(timezone.stname[0] == 0)
803e12c5d1SDavid du Colombier 		readtimezone();
813e12c5d1SDavid du Colombier 	t = tim + timezone.stdiff;
823e12c5d1SDavid du Colombier 	dlflag = 0;
833e12c5d1SDavid du Colombier 	for(p = timezone.dlpairs; *p; p += 2)
843e12c5d1SDavid du Colombier 		if(t >= p[0])
853e12c5d1SDavid du Colombier 		if(t < p[1]) {
863e12c5d1SDavid du Colombier 			t = tim + timezone.dldiff;
873e12c5d1SDavid du Colombier 			dlflag++;
883e12c5d1SDavid du Colombier 			break;
893e12c5d1SDavid du Colombier 		}
903e12c5d1SDavid du Colombier 	ct = gmtime(t);
917dd7cddfSDavid du Colombier 	if(dlflag){
927dd7cddfSDavid du Colombier 		strcpy(ct->zone, timezone.dlname);
937dd7cddfSDavid du Colombier 		ct->tzoff = timezone.dldiff;
947dd7cddfSDavid du Colombier 	} else {
957dd7cddfSDavid du Colombier 		strcpy(ct->zone, timezone.stname);
967dd7cddfSDavid du Colombier 		ct->tzoff = timezone.stdiff;
977dd7cddfSDavid du Colombier 	}
983e12c5d1SDavid du Colombier 	return ct;
993e12c5d1SDavid du Colombier }
1003e12c5d1SDavid du Colombier 
1013e12c5d1SDavid du Colombier Tm*
gmtime(long atim)102*54dec067SDavid du Colombier gmtime(long atim)		/* should be ulong, but it's too late */
1033e12c5d1SDavid du Colombier {
1043e12c5d1SDavid du Colombier 	int d0, d1;
1053e12c5d1SDavid du Colombier 	long hms, day;
106*54dec067SDavid du Colombier 	ulong tim;
1073e12c5d1SDavid du Colombier 	static Tm xtime;
1083e12c5d1SDavid du Colombier 
1093e12c5d1SDavid du Colombier 	/*
1103e12c5d1SDavid du Colombier 	 * break initial number into days
1113e12c5d1SDavid du Colombier 	 */
112*54dec067SDavid du Colombier 	tim = atim;
113*54dec067SDavid du Colombier 	hms = tim % 86400L;
114*54dec067SDavid du Colombier 	day = tim / 86400L;
1153e12c5d1SDavid du Colombier 	if(hms < 0) {
1163e12c5d1SDavid du Colombier 		hms += 86400L;
1173e12c5d1SDavid du Colombier 		day -= 1;
1183e12c5d1SDavid du Colombier 	}
1193e12c5d1SDavid du Colombier 
1203e12c5d1SDavid du Colombier 	/*
1213e12c5d1SDavid du Colombier 	 * generate hours:minutes:seconds
1223e12c5d1SDavid du Colombier 	 */
1233e12c5d1SDavid du Colombier 	xtime.sec = hms % 60;
1243e12c5d1SDavid du Colombier 	d1 = hms / 60;
1253e12c5d1SDavid du Colombier 	xtime.min = d1 % 60;
1263e12c5d1SDavid du Colombier 	d1 /= 60;
1273e12c5d1SDavid du Colombier 	xtime.hour = d1;
1283e12c5d1SDavid du Colombier 
1293e12c5d1SDavid du Colombier 	/*
1303e12c5d1SDavid du Colombier 	 * day is the day number.
1313e12c5d1SDavid du Colombier 	 * generate day of the week.
1323e12c5d1SDavid du Colombier 	 * The addend is 4 mod 7 (1/1/1970 was Thursday)
1333e12c5d1SDavid du Colombier 	 */
1343e12c5d1SDavid du Colombier 
1353e12c5d1SDavid du Colombier 	xtime.wday = (day + 7340036L) % 7;
1363e12c5d1SDavid du Colombier 
1373e12c5d1SDavid du Colombier 	/*
1383e12c5d1SDavid du Colombier 	 * year number
1393e12c5d1SDavid du Colombier 	 */
1403e12c5d1SDavid du Colombier 	if(day >= 0)
1417dd7cddfSDavid du Colombier 		for(d1 = 1970; day >= dysize(d1); d1++)
1423e12c5d1SDavid du Colombier 			day -= dysize(d1);
1433e12c5d1SDavid du Colombier 	else
1447dd7cddfSDavid du Colombier 		for (d1 = 1970; day < 0; d1--)
1453e12c5d1SDavid du Colombier 			day += dysize(d1-1);
1467dd7cddfSDavid du Colombier 	xtime.year = d1-1900;
1473e12c5d1SDavid du Colombier 	xtime.yday = d0 = day;
1483e12c5d1SDavid du Colombier 
1493e12c5d1SDavid du Colombier 	/*
1503e12c5d1SDavid du Colombier 	 * generate month
1513e12c5d1SDavid du Colombier 	 */
1523e12c5d1SDavid du Colombier 
1533e12c5d1SDavid du Colombier 	if(dysize(d1) == 366)
1543e12c5d1SDavid du Colombier 		dmsize[1] = 29;
1553e12c5d1SDavid du Colombier 	for(d1 = 0; d0 >= dmsize[d1]; d1++)
1563e12c5d1SDavid du Colombier 		d0 -= dmsize[d1];
1573e12c5d1SDavid du Colombier 	dmsize[1] = 28;
1583e12c5d1SDavid du Colombier 	xtime.mday = d0 + 1;
1593e12c5d1SDavid du Colombier 	xtime.mon = d1;
1603e12c5d1SDavid du Colombier 	strcpy(xtime.zone, "GMT");
1613e12c5d1SDavid du Colombier 	return &xtime;
1623e12c5d1SDavid du Colombier }
1633e12c5d1SDavid du Colombier 
1643e12c5d1SDavid du Colombier char*
asctime(Tm * t)1653e12c5d1SDavid du Colombier asctime(Tm *t)
1663e12c5d1SDavid du Colombier {
1673e12c5d1SDavid du Colombier 	char *ncp;
1683e12c5d1SDavid du Colombier 	static char cbuf[30];
1693e12c5d1SDavid du Colombier 
1703e12c5d1SDavid du Colombier 	strcpy(cbuf, "Thu Jan 01 00:00:00 GMT 1970\n");
1713e12c5d1SDavid du Colombier 	ncp = &"SunMonTueWedThuFriSat"[t->wday*3];
1723e12c5d1SDavid du Colombier 	cbuf[0] = *ncp++;
1733e12c5d1SDavid du Colombier 	cbuf[1] = *ncp++;
1743e12c5d1SDavid du Colombier 	cbuf[2] = *ncp;
1753e12c5d1SDavid du Colombier 	ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[t->mon*3];
1763e12c5d1SDavid du Colombier 	cbuf[4] = *ncp++;
1773e12c5d1SDavid du Colombier 	cbuf[5] = *ncp++;
1783e12c5d1SDavid du Colombier 	cbuf[6] = *ncp;
1793e12c5d1SDavid du Colombier 	ct_numb(cbuf+8, t->mday);
1803e12c5d1SDavid du Colombier 	ct_numb(cbuf+11, t->hour+100);
1813e12c5d1SDavid du Colombier 	ct_numb(cbuf+14, t->min+100);
1823e12c5d1SDavid du Colombier 	ct_numb(cbuf+17, t->sec+100);
1833e12c5d1SDavid du Colombier 	ncp = t->zone;
1843e12c5d1SDavid du Colombier 	cbuf[20] = *ncp++;
1853e12c5d1SDavid du Colombier 	cbuf[21] = *ncp++;
1863e12c5d1SDavid du Colombier 	cbuf[22] = *ncp;
1873e12c5d1SDavid du Colombier 	if(t->year >= 100) {
1883e12c5d1SDavid du Colombier 		cbuf[24] = '2';
189*54dec067SDavid du Colombier 		cbuf[25] = '0';
1903e12c5d1SDavid du Colombier 	}
1913e12c5d1SDavid du Colombier 	ct_numb(cbuf+26, t->year+100);
1923e12c5d1SDavid du Colombier 	return cbuf;
1933e12c5d1SDavid du Colombier }
1943e12c5d1SDavid du Colombier 
1953e12c5d1SDavid du Colombier static
dysize(int y)1963e12c5d1SDavid du Colombier dysize(int y)
1973e12c5d1SDavid du Colombier {
1983e12c5d1SDavid du Colombier 
1997dd7cddfSDavid du Colombier 	if(y%4 == 0 && (y%100 != 0 || y%400 == 0))
2003e12c5d1SDavid du Colombier 		return 366;
2013e12c5d1SDavid du Colombier 	return 365;
2023e12c5d1SDavid du Colombier }
2033e12c5d1SDavid du Colombier 
2043e12c5d1SDavid du Colombier static
2053e12c5d1SDavid du Colombier void
ct_numb(char * cp,int n)2063e12c5d1SDavid du Colombier ct_numb(char *cp, int n)
2073e12c5d1SDavid du Colombier {
2083e12c5d1SDavid du Colombier 
2093e12c5d1SDavid du Colombier 	cp[0] = ' ';
2103e12c5d1SDavid du Colombier 	if(n >= 10)
2113e12c5d1SDavid du Colombier 		cp[0] = (n/10)%10 + '0';
2123e12c5d1SDavid du Colombier 	cp[1] = n%10 + '0';
2133e12c5d1SDavid du Colombier }
2143e12c5d1SDavid du Colombier 
2153e12c5d1SDavid du Colombier static
2163e12c5d1SDavid du Colombier void
readtimezone(void)2173e12c5d1SDavid du Colombier readtimezone(void)
2183e12c5d1SDavid du Colombier {
2193e12c5d1SDavid du Colombier 	char buf[TZSIZE*11+30], *p;
2203e12c5d1SDavid du Colombier 	int i;
2213e12c5d1SDavid du Colombier 
2223e12c5d1SDavid du Colombier 	memset(buf, 0, sizeof(buf));
2233e12c5d1SDavid du Colombier 	i = open("/env/timezone", 0);
2243e12c5d1SDavid du Colombier 	if(i < 0)
2253e12c5d1SDavid du Colombier 		goto error;
2263b56890dSDavid du Colombier 	if(read(i, buf, sizeof(buf)) >= sizeof(buf)){
2273b56890dSDavid du Colombier 		close(i);
2283e12c5d1SDavid du Colombier 		goto error;
2293b56890dSDavid du Colombier 	}
2303e12c5d1SDavid du Colombier 	close(i);
2313e12c5d1SDavid du Colombier 	p = buf;
2323e12c5d1SDavid du Colombier 	if(rd_name(&p, timezone.stname))
2333e12c5d1SDavid du Colombier 		goto error;
2343e12c5d1SDavid du Colombier 	if(rd_long(&p, &timezone.stdiff))
2353e12c5d1SDavid du Colombier 		goto error;
2363e12c5d1SDavid du Colombier 	if(rd_name(&p, timezone.dlname))
2373e12c5d1SDavid du Colombier 		goto error;
2383e12c5d1SDavid du Colombier 	if(rd_long(&p, &timezone.dldiff))
2393e12c5d1SDavid du Colombier 		goto error;
2403e12c5d1SDavid du Colombier 	for(i=0; i<TZSIZE; i++) {
241*54dec067SDavid du Colombier 		if(rd_long(&p, (long *)&timezone.dlpairs[i]))
2423e12c5d1SDavid du Colombier 			goto error;
2433e12c5d1SDavid du Colombier 		if(timezone.dlpairs[i] == 0)
2443e12c5d1SDavid du Colombier 			return;
2453e12c5d1SDavid du Colombier 	}
246*54dec067SDavid du Colombier 	/* array too small for input */
2473e12c5d1SDavid du Colombier error:
2483e12c5d1SDavid du Colombier 	timezone.stdiff = 0;
2493e12c5d1SDavid du Colombier 	strcpy(timezone.stname, "GMT");
2503e12c5d1SDavid du Colombier 	timezone.dlpairs[0] = 0;
2513e12c5d1SDavid du Colombier }
2523e12c5d1SDavid du Colombier 
2533e12c5d1SDavid du Colombier static
rd_name(char ** f,char * p)2543e12c5d1SDavid du Colombier rd_name(char **f, char *p)
2553e12c5d1SDavid du Colombier {
2563e12c5d1SDavid du Colombier 	int c, i;
2573e12c5d1SDavid du Colombier 
2583e12c5d1SDavid du Colombier 	for(;;) {
2593e12c5d1SDavid du Colombier 		c = *(*f)++;
2603e12c5d1SDavid du Colombier 		if(c != ' ' && c != '\n')
2613e12c5d1SDavid du Colombier 			break;
2623e12c5d1SDavid du Colombier 	}
2633e12c5d1SDavid du Colombier 	for(i=0; i<3; i++) {
2643e12c5d1SDavid du Colombier 		if(c == ' ' || c == '\n')
2653e12c5d1SDavid du Colombier 			return 1;
2663e12c5d1SDavid du Colombier 		*p++ = c;
2673e12c5d1SDavid du Colombier 		c = *(*f)++;
2683e12c5d1SDavid du Colombier 	}
2693e12c5d1SDavid du Colombier 	if(c != ' ' && c != '\n')
2703e12c5d1SDavid du Colombier 		return 1;
2713e12c5d1SDavid du Colombier 	*p = 0;
2723e12c5d1SDavid du Colombier 	return 0;
2733e12c5d1SDavid du Colombier }
2743e12c5d1SDavid du Colombier 
2753e12c5d1SDavid du Colombier static
rd_long(char ** f,long * p)2763e12c5d1SDavid du Colombier rd_long(char **f, long *p)
2773e12c5d1SDavid du Colombier {
2783e12c5d1SDavid du Colombier 	int c, s;
2793e12c5d1SDavid du Colombier 	long l;
2803e12c5d1SDavid du Colombier 
2813e12c5d1SDavid du Colombier 	s = 0;
2823e12c5d1SDavid du Colombier 	for(;;) {
2833e12c5d1SDavid du Colombier 		c = *(*f)++;
2843e12c5d1SDavid du Colombier 		if(c == '-') {
2853e12c5d1SDavid du Colombier 			s++;
2863e12c5d1SDavid du Colombier 			continue;
2873e12c5d1SDavid du Colombier 		}
2883e12c5d1SDavid du Colombier 		if(c != ' ' && c != '\n')
2893e12c5d1SDavid du Colombier 			break;
2903e12c5d1SDavid du Colombier 	}
2913e12c5d1SDavid du Colombier 	if(c == 0) {
2923e12c5d1SDavid du Colombier 		*p = 0;
2933e12c5d1SDavid du Colombier 		return 0;
2943e12c5d1SDavid du Colombier 	}
2953e12c5d1SDavid du Colombier 	l = 0;
2963e12c5d1SDavid du Colombier 	for(;;) {
2973e12c5d1SDavid du Colombier 		if(c == ' ' || c == '\n')
2983e12c5d1SDavid du Colombier 			break;
2993e12c5d1SDavid du Colombier 		if(c < '0' || c > '9')
3003e12c5d1SDavid du Colombier 			return 1;
3013e12c5d1SDavid du Colombier 		l = l*10 + c-'0';
3023e12c5d1SDavid du Colombier 		c = *(*f)++;
3033e12c5d1SDavid du Colombier 	}
3043e12c5d1SDavid du Colombier 	if(s)
3053e12c5d1SDavid du Colombier 		l = -l;
3063e12c5d1SDavid du Colombier 	*p = l;
3073e12c5d1SDavid du Colombier 	return 0;
3083e12c5d1SDavid du Colombier }
309