xref: /plan9/sys/src/libc/9sys/tm2sec.c (revision 07a38badf213997c31d1c5333bda042c200ae172)
1 #include <u.h>
2 #include <libc.h>
3 
4 #define	TZSIZE	150
5 static	void	readtimezone(void);
6 static	int	rd_name(char**, char*);
7 static	int	rd_long(char**, long*);
8 static
9 struct
10 {
11 	char	stname[4];
12 	char	dlname[4];
13 	long	stdiff;
14 	long	dldiff;
15 	long	dlpairs[TZSIZE];
16 } timezone;
17 
18 #define SEC2MIN 60L
19 #define SEC2HOUR (60L*SEC2MIN)
20 #define SEC2DAY (24L*SEC2HOUR)
21 
22 /*
23  *  days per month plus days/year
24  */
25 static	int	dmsize[] =
26 {
27 	365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
28 };
29 static	int	ldmsize[] =
30 {
31 	366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
32 };
33 
34 /*
35  *  return the days/month for the given year
36  */
37 static int *
yrsize(int y)38 yrsize(int y)
39 {
40 	if((y%4) == 0 && ((y%100) != 0 || (y%400) == 0))
41 		return ldmsize;
42 	else
43 		return dmsize;
44 }
45 
46 /*
47  * compute seconds since Jan 1 1970 GMT
48  * and convert to our timezone.
49  */
50 long
tm2sec(Tm * tm)51 tm2sec(Tm *tm)
52 {
53 	long secs;
54 	int i, yday, year, *d2m;
55 
56 	if(strcmp(tm->zone, "GMT") != 0 && timezone.stname[0] == 0)
57 		readtimezone();
58 	secs = 0;
59 
60 	/*
61 	 *  seconds per year
62 	 */
63 	year = tm->year + 1900;
64 	for(i = 1970; i < year; i++){
65 		d2m = yrsize(i);
66 		secs += d2m[0] * SEC2DAY;
67 	}
68 
69 	/*
70 	 *  if mday is set, use mon and mday to compute yday
71 	 */
72 	if(tm->mday){
73 		yday = 0;
74 		d2m = yrsize(year);
75 		for(i=0; i<tm->mon; i++)
76 			yday += d2m[i+1];
77 		yday += tm->mday-1;
78 	}else{
79 		yday = tm->yday;
80 	}
81 	secs += yday * SEC2DAY;
82 
83 	/*
84 	 * hours, minutes, seconds
85 	 */
86 	secs += tm->hour * SEC2HOUR;
87 	secs += tm->min * SEC2MIN;
88 	secs += tm->sec;
89 
90 	/*
91 	 * Only handles zones mentioned in /env/timezone,
92 	 * but things get too ambiguous otherwise.
93 	 */
94 	if(strcmp(tm->zone, timezone.stname) == 0)
95 		secs -= timezone.stdiff;
96 	else if(strcmp(tm->zone, timezone.dlname) == 0)
97 		secs -= timezone.dldiff;
98 	if(secs < 0)
99 		secs = 0;
100 	return secs;
101 }
102 
103 static
104 void
readtimezone(void)105 readtimezone(void)
106 {
107 	char buf[TZSIZE*11+30], *p;
108 	int i;
109 
110 	memset(buf, 0, sizeof(buf));
111 	i = open("/env/timezone", 0);
112 	if(i < 0)
113 		goto error;
114 	if(read(i, buf, sizeof(buf)) >= sizeof(buf))
115 		goto error;
116 	close(i);
117 	p = buf;
118 	if(rd_name(&p, timezone.stname))
119 		goto error;
120 	if(rd_long(&p, &timezone.stdiff))
121 		goto error;
122 	if(rd_name(&p, timezone.dlname))
123 		goto error;
124 	if(rd_long(&p, &timezone.dldiff))
125 		goto error;
126 	for(i=0; i<TZSIZE; i++) {
127 		if(rd_long(&p, &timezone.dlpairs[i]))
128 			goto error;
129 		if(timezone.dlpairs[i] == 0)
130 			return;
131 	}
132 
133 error:
134 	timezone.stdiff = 0;
135 	strcpy(timezone.stname, "GMT");
136 	timezone.dlpairs[0] = 0;
137 }
138 
139 static int
rd_name(char ** f,char * p)140 rd_name(char **f, char *p)
141 {
142 	int c, i;
143 
144 	for(;;) {
145 		c = *(*f)++;
146 		if(c != ' ' && c != '\n')
147 			break;
148 	}
149 	for(i=0; i<3; i++) {
150 		if(c == ' ' || c == '\n')
151 			return 1;
152 		*p++ = c;
153 		c = *(*f)++;
154 	}
155 	if(c != ' ' && c != '\n')
156 		return 1;
157 	*p = 0;
158 	return 0;
159 }
160 
161 static int
rd_long(char ** f,long * p)162 rd_long(char **f, long *p)
163 {
164 	int c, s;
165 	long l;
166 
167 	s = 0;
168 	for(;;) {
169 		c = *(*f)++;
170 		if(c == '-') {
171 			s++;
172 			continue;
173 		}
174 		if(c != ' ' && c != '\n')
175 			break;
176 	}
177 	if(c == 0) {
178 		*p = 0;
179 		return 0;
180 	}
181 	l = 0;
182 	for(;;) {
183 		if(c == ' ' || c == '\n')
184 			break;
185 		if(c < '0' || c > '9')
186 			return 1;
187 		l = l*10 + c-'0';
188 		c = *(*f)++;
189 	}
190 	if(s)
191 		l = -l;
192 	*p = l;
193 	return 0;
194 }
195