xref: /plan9-contrib/sys/src/libc/9sys/tm2sec.c (revision 54dec0678461a9d7af09e995e96ae173d1daa5c7)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier 
4*54dec067SDavid du Colombier #define	TZSIZE	((136*2)+10)		/* 1970-2106; match tm2sec.c */
5*54dec067SDavid du Colombier 
67dd7cddfSDavid du Colombier static	void	readtimezone(void);
77dd7cddfSDavid du Colombier static	int	rd_name(char**, char*);
87dd7cddfSDavid du Colombier static	int	rd_long(char**, long*);
9*54dec067SDavid du Colombier 
107dd7cddfSDavid du Colombier static
117dd7cddfSDavid du Colombier struct
127dd7cddfSDavid du Colombier {
137dd7cddfSDavid du Colombier 	char	stname[4];
147dd7cddfSDavid du Colombier 	char	dlname[4];
157dd7cddfSDavid du Colombier 	long	stdiff;
167dd7cddfSDavid du Colombier 	long	dldiff;
17*54dec067SDavid du Colombier 	ulong	dlpairs[TZSIZE];
187dd7cddfSDavid du Colombier } timezone;
197dd7cddfSDavid du Colombier 
20*54dec067SDavid du Colombier #define SEC2MIN 60UL
21*54dec067SDavid du Colombier #define SEC2HOUR (60UL*SEC2MIN)
22*54dec067SDavid du Colombier #define SEC2DAY (24UL*SEC2HOUR)
237dd7cddfSDavid du Colombier 
247dd7cddfSDavid du Colombier /*
257dd7cddfSDavid du Colombier  *  days per month plus days/year
267dd7cddfSDavid du Colombier  */
277dd7cddfSDavid du Colombier static	int	dmsize[] =
287dd7cddfSDavid du Colombier {
297dd7cddfSDavid du Colombier 	365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
307dd7cddfSDavid du Colombier };
317dd7cddfSDavid du Colombier static	int	ldmsize[] =
327dd7cddfSDavid du Colombier {
337dd7cddfSDavid du Colombier 	366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
347dd7cddfSDavid du Colombier };
357dd7cddfSDavid du Colombier 
367dd7cddfSDavid du Colombier /*
377dd7cddfSDavid du Colombier  *  return the days/month for the given year
387dd7cddfSDavid du Colombier  */
397dd7cddfSDavid du Colombier static int *
yrsize(int y)407dd7cddfSDavid du Colombier yrsize(int y)
417dd7cddfSDavid du Colombier {
427dd7cddfSDavid du Colombier 	if((y%4) == 0 && ((y%100) != 0 || (y%400) == 0))
437dd7cddfSDavid du Colombier 		return ldmsize;
447dd7cddfSDavid du Colombier 	else
457dd7cddfSDavid du Colombier 		return dmsize;
467dd7cddfSDavid du Colombier }
477dd7cddfSDavid du Colombier 
487dd7cddfSDavid du Colombier /*
497dd7cddfSDavid du Colombier  * compute seconds since Jan 1 1970 GMT
507dd7cddfSDavid du Colombier  * and convert to our timezone.
517dd7cddfSDavid du Colombier  */
527dd7cddfSDavid du Colombier long
tm2sec(Tm * tm)537dd7cddfSDavid du Colombier tm2sec(Tm *tm)
547dd7cddfSDavid du Colombier {
55*54dec067SDavid du Colombier 	ulong secs;
5607a38badSDavid du Colombier 	int i, yday, year, *d2m;
577dd7cddfSDavid du Colombier 
587dd7cddfSDavid du Colombier 	if(strcmp(tm->zone, "GMT") != 0 && timezone.stname[0] == 0)
597dd7cddfSDavid du Colombier 		readtimezone();
607dd7cddfSDavid du Colombier 	secs = 0;
617dd7cddfSDavid du Colombier 
627dd7cddfSDavid du Colombier 	/*
637dd7cddfSDavid du Colombier 	 *  seconds per year
647dd7cddfSDavid du Colombier 	 */
657dd7cddfSDavid du Colombier 	year = tm->year + 1900;
667dd7cddfSDavid du Colombier 	for(i = 1970; i < year; i++){
677dd7cddfSDavid du Colombier 		d2m = yrsize(i);
687dd7cddfSDavid du Colombier 		secs += d2m[0] * SEC2DAY;
697dd7cddfSDavid du Colombier 	}
707dd7cddfSDavid du Colombier 
717dd7cddfSDavid du Colombier 	/*
7207a38badSDavid du Colombier 	 *  if mday is set, use mon and mday to compute yday
736b6b9ac8SDavid du Colombier 	 */
7407a38badSDavid du Colombier 	if(tm->mday){
7507a38badSDavid du Colombier 		yday = 0;
767dd7cddfSDavid du Colombier 		d2m = yrsize(year);
777dd7cddfSDavid du Colombier 		for(i=0; i<tm->mon; i++)
7807a38badSDavid du Colombier 			yday += d2m[i+1];
7907a38badSDavid du Colombier 		yday += tm->mday-1;
8007a38badSDavid du Colombier 	}else{
8107a38badSDavid du Colombier 		yday = tm->yday;
826b6b9ac8SDavid du Colombier 	}
8307a38badSDavid du Colombier 	secs += yday * SEC2DAY;
847dd7cddfSDavid du Colombier 
857dd7cddfSDavid du Colombier 	/*
867dd7cddfSDavid du Colombier 	 * hours, minutes, seconds
877dd7cddfSDavid du Colombier 	 */
887dd7cddfSDavid du Colombier 	secs += tm->hour * SEC2HOUR;
897dd7cddfSDavid du Colombier 	secs += tm->min * SEC2MIN;
907dd7cddfSDavid du Colombier 	secs += tm->sec;
917dd7cddfSDavid du Colombier 
927dd7cddfSDavid du Colombier 	/*
93d9306527SDavid du Colombier 	 * Only handles zones mentioned in /env/timezone,
94d9306527SDavid du Colombier 	 * but things get too ambiguous otherwise.
957dd7cddfSDavid du Colombier 	 */
96d9306527SDavid du Colombier 	if(strcmp(tm->zone, timezone.stname) == 0)
97d9306527SDavid du Colombier 		secs -= timezone.stdiff;
98d9306527SDavid du Colombier 	else if(strcmp(tm->zone, timezone.dlname) == 0)
99d9306527SDavid du Colombier 		secs -= timezone.dldiff;
1007dd7cddfSDavid du Colombier 	return secs;
1017dd7cddfSDavid du Colombier }
1027dd7cddfSDavid du Colombier 
1037dd7cddfSDavid du Colombier static
1047dd7cddfSDavid du Colombier void
readtimezone(void)1057dd7cddfSDavid du Colombier readtimezone(void)
1067dd7cddfSDavid du Colombier {
1077dd7cddfSDavid du Colombier 	char buf[TZSIZE*11+30], *p;
1087dd7cddfSDavid du Colombier 	int i;
1097dd7cddfSDavid du Colombier 
1107dd7cddfSDavid du Colombier 	memset(buf, 0, sizeof(buf));
1117dd7cddfSDavid du Colombier 	i = open("/env/timezone", 0);
1127dd7cddfSDavid du Colombier 	if(i < 0)
1137dd7cddfSDavid du Colombier 		goto error;
1147dd7cddfSDavid du Colombier 	if(read(i, buf, sizeof(buf)) >= sizeof(buf))
1157dd7cddfSDavid du Colombier 		goto error;
1167dd7cddfSDavid du Colombier 	close(i);
1177dd7cddfSDavid du Colombier 	p = buf;
1187dd7cddfSDavid du Colombier 	if(rd_name(&p, timezone.stname))
1197dd7cddfSDavid du Colombier 		goto error;
1207dd7cddfSDavid du Colombier 	if(rd_long(&p, &timezone.stdiff))
1217dd7cddfSDavid du Colombier 		goto error;
1227dd7cddfSDavid du Colombier 	if(rd_name(&p, timezone.dlname))
1237dd7cddfSDavid du Colombier 		goto error;
1247dd7cddfSDavid du Colombier 	if(rd_long(&p, &timezone.dldiff))
1257dd7cddfSDavid du Colombier 		goto error;
1267dd7cddfSDavid du Colombier 	for(i=0; i<TZSIZE; i++) {
127*54dec067SDavid du Colombier 		if(rd_long(&p, (long *)&timezone.dlpairs[i]))
1287dd7cddfSDavid du Colombier 			goto error;
1297dd7cddfSDavid du Colombier 		if(timezone.dlpairs[i] == 0)
1307dd7cddfSDavid du Colombier 			return;
1317dd7cddfSDavid du Colombier 	}
132*54dec067SDavid du Colombier 	/* array too small for input */
1337dd7cddfSDavid du Colombier error:
1347dd7cddfSDavid du Colombier 	timezone.stdiff = 0;
1357dd7cddfSDavid du Colombier 	strcpy(timezone.stname, "GMT");
1367dd7cddfSDavid du Colombier 	timezone.dlpairs[0] = 0;
1377dd7cddfSDavid du Colombier }
1387dd7cddfSDavid du Colombier 
1397dd7cddfSDavid du Colombier static int
rd_name(char ** f,char * p)1407dd7cddfSDavid du Colombier rd_name(char **f, char *p)
1417dd7cddfSDavid du Colombier {
1427dd7cddfSDavid du Colombier 	int c, i;
1437dd7cddfSDavid du Colombier 
1447dd7cddfSDavid du Colombier 	for(;;) {
1457dd7cddfSDavid du Colombier 		c = *(*f)++;
1467dd7cddfSDavid du Colombier 		if(c != ' ' && c != '\n')
1477dd7cddfSDavid du Colombier 			break;
1487dd7cddfSDavid du Colombier 	}
1497dd7cddfSDavid du Colombier 	for(i=0; i<3; i++) {
1507dd7cddfSDavid du Colombier 		if(c == ' ' || c == '\n')
1517dd7cddfSDavid du Colombier 			return 1;
1527dd7cddfSDavid du Colombier 		*p++ = c;
1537dd7cddfSDavid du Colombier 		c = *(*f)++;
1547dd7cddfSDavid du Colombier 	}
1557dd7cddfSDavid du Colombier 	if(c != ' ' && c != '\n')
1567dd7cddfSDavid du Colombier 		return 1;
1577dd7cddfSDavid du Colombier 	*p = 0;
1587dd7cddfSDavid du Colombier 	return 0;
1597dd7cddfSDavid du Colombier }
1607dd7cddfSDavid du Colombier 
1617dd7cddfSDavid du Colombier static int
rd_long(char ** f,long * p)1627dd7cddfSDavid du Colombier rd_long(char **f, long *p)
1637dd7cddfSDavid du Colombier {
1647dd7cddfSDavid du Colombier 	int c, s;
1657dd7cddfSDavid du Colombier 	long l;
1667dd7cddfSDavid du Colombier 
1677dd7cddfSDavid du Colombier 	s = 0;
1687dd7cddfSDavid du Colombier 	for(;;) {
1697dd7cddfSDavid du Colombier 		c = *(*f)++;
1707dd7cddfSDavid du Colombier 		if(c == '-') {
1717dd7cddfSDavid du Colombier 			s++;
1727dd7cddfSDavid du Colombier 			continue;
1737dd7cddfSDavid du Colombier 		}
1747dd7cddfSDavid du Colombier 		if(c != ' ' && c != '\n')
1757dd7cddfSDavid du Colombier 			break;
1767dd7cddfSDavid du Colombier 	}
1777dd7cddfSDavid du Colombier 	if(c == 0) {
1787dd7cddfSDavid du Colombier 		*p = 0;
1797dd7cddfSDavid du Colombier 		return 0;
1807dd7cddfSDavid du Colombier 	}
1817dd7cddfSDavid du Colombier 	l = 0;
1827dd7cddfSDavid du Colombier 	for(;;) {
1837dd7cddfSDavid du Colombier 		if(c == ' ' || c == '\n')
1847dd7cddfSDavid du Colombier 			break;
1857dd7cddfSDavid du Colombier 		if(c < '0' || c > '9')
1867dd7cddfSDavid du Colombier 			return 1;
1877dd7cddfSDavid du Colombier 		l = l*10 + c-'0';
1887dd7cddfSDavid du Colombier 		c = *(*f)++;
1897dd7cddfSDavid du Colombier 	}
1907dd7cddfSDavid du Colombier 	if(s)
1917dd7cddfSDavid du Colombier 		l = -l;
1927dd7cddfSDavid du Colombier 	*p = l;
1937dd7cddfSDavid du Colombier 	return 0;
1947dd7cddfSDavid du Colombier }
195