xref: /plan9-contrib/sys/src/libc/9sys/tm2sec.c (revision d46c239f8612929b7dbade67d0d071633df3a15d)
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 *
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
51 tm2sec(Tm *tm)
52 {
53 	long secs;
54 	int i, 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 	 *  seconds per month
71 	 */
72 	d2m = yrsize(year);
73 	for(i = 0; i < tm->mon; i++)
74 		secs += d2m[i+1] * SEC2DAY;
75 
76 	/*
77 	 * secs in last month
78 	 */
79 	secs += (tm->mday-1) * SEC2DAY;
80 
81 	/*
82 	 * hours, minutes, seconds
83 	 */
84 	secs += tm->hour * SEC2HOUR;
85 	secs += tm->min * SEC2MIN;
86 	secs += tm->sec;
87 
88 	/*
89 	 * Only handles zones mentioned in /env/timezone,
90 	 * but things get too ambiguous otherwise.
91 	 */
92 	if(strcmp(tm->zone, timezone.stname) == 0)
93 		secs -= timezone.stdiff;
94 	else if(strcmp(tm->zone, timezone.dlname) == 0)
95 		secs -= timezone.dldiff;
96 	if(secs < 0)
97 		secs = 0;
98 	return secs;
99 }
100 
101 static
102 void
103 readtimezone(void)
104 {
105 	char buf[TZSIZE*11+30], *p;
106 	int i;
107 
108 	memset(buf, 0, sizeof(buf));
109 	i = open("/env/timezone", 0);
110 	if(i < 0)
111 		goto error;
112 	if(read(i, buf, sizeof(buf)) >= sizeof(buf))
113 		goto error;
114 	close(i);
115 	p = buf;
116 	if(rd_name(&p, timezone.stname))
117 		goto error;
118 	if(rd_long(&p, &timezone.stdiff))
119 		goto error;
120 	if(rd_name(&p, timezone.dlname))
121 		goto error;
122 	if(rd_long(&p, &timezone.dldiff))
123 		goto error;
124 	for(i=0; i<TZSIZE; i++) {
125 		if(rd_long(&p, &timezone.dlpairs[i]))
126 			goto error;
127 		if(timezone.dlpairs[i] == 0)
128 			return;
129 	}
130 
131 error:
132 	timezone.stdiff = 0;
133 	strcpy(timezone.stname, "GMT");
134 	timezone.dlpairs[0] = 0;
135 }
136 
137 static int
138 rd_name(char **f, char *p)
139 {
140 	int c, i;
141 
142 	for(;;) {
143 		c = *(*f)++;
144 		if(c != ' ' && c != '\n')
145 			break;
146 	}
147 	for(i=0; i<3; i++) {
148 		if(c == ' ' || c == '\n')
149 			return 1;
150 		*p++ = c;
151 		c = *(*f)++;
152 	}
153 	if(c != ' ' && c != '\n')
154 		return 1;
155 	*p = 0;
156 	return 0;
157 }
158 
159 static int
160 rd_long(char **f, long *p)
161 {
162 	int c, s;
163 	long l;
164 
165 	s = 0;
166 	for(;;) {
167 		c = *(*f)++;
168 		if(c == '-') {
169 			s++;
170 			continue;
171 		}
172 		if(c != ' ' && c != '\n')
173 			break;
174 	}
175 	if(c == 0) {
176 		*p = 0;
177 		return 0;
178 	}
179 	l = 0;
180 	for(;;) {
181 		if(c == ' ' || c == '\n')
182 			break;
183 		if(c < '0' || c > '9')
184 			return 1;
185 		l = l*10 + c-'0';
186 		c = *(*f)++;
187 	}
188 	if(s)
189 		l = -l;
190 	*p = l;
191 	return 0;
192 }
193