xref: /plan9/sys/src/cmd/astro/pdate.c (revision 59cc4ca53493a3c6d2349fe2b7f7c40f7dce7294)
1 #include "astro.h"
2 
3 
4 char*	month[] =
5 {
6 	"January",
7 	"February",
8 	"March",
9 	"April",
10 	"May",
11 	"June",
12 	"July",
13 	"August",
14 	"September",
15 	"October",
16 	"November",
17 	"December",
18 };
19 
20 double
dsrc(double d,Tim * t,int i)21 dsrc(double d, Tim *t, int i)
22 {
23 	double y;
24 
25 	do {
26 		t->ifa[i] += 1.;
27 		y = convdate(t);
28 	} while(d >= y);
29 	do {
30 		t->ifa[i] -= 1.;
31 		y = convdate(t);
32 	} while(d < y);
33 	return d - y;
34 }
35 
36 void
dtsetup(double d,Tim * t)37 dtsetup(double d, Tim *t)
38 {
39 	double v;
40 
41 	t->ifa[0] = floor(1900 + d/365.24220);
42 	t->ifa[1] = 1;
43 	t->ifa[2] = 1;
44 	t->ifa[3] = 0;
45 	t->ifa[4] = 0;
46 	t->ifa[1] = floor(1 + dsrc(d, t, 0)/30);
47 	t->ifa[2] = floor(1 + dsrc(d, t, 1));
48 	dsrc(d, t, 2);
49 
50 	v = (d - convdate(t)) * 24;
51 	t->ifa[3] = floor(v);
52 	t->ifa[4] = (v - t->ifa[3]) * 60;
53 	convdate(t);	/* to set timezone */
54 }
55 
56 void
pdate(double d)57 pdate(double d)
58 {
59 	int i;
60 	Tim t;
61 
62 	dtsetup(d, &t);
63 	if(flags['s']) {
64 		i = t.ifa[1];
65 		print("%s ", month[i-1]);
66 		i = t.ifa[2];
67 		numb(i);
68 		print("...");
69 		return;
70 	}
71 
72 	/* year month day */
73 	print("%4d %2d %2d",
74 		(int)t.ifa[0],
75 		(int)t.ifa[1],
76 		(int)t.ifa[2]);
77 }
78 
79 void
ptime(double d)80 ptime(double d)
81 {
82 	int h, m, s;
83 	char *mer;
84 	Tim t;
85 
86 	if(flags['s']) {
87 		/* hour minute */
88 		dtsetup(d + .5/(24*60), &t);
89 		h = t.ifa[3];
90 		m = floor(t.ifa[4]);
91 
92 		mer = "AM";
93 		if(h >= 12) {
94 			mer = "PM";
95 			h -= 12;
96 		}
97 		if(h == 0)
98 			h = 12;
99 		numb(h);
100 		if(m < 10) {
101 			if(m == 0) {
102 				print("%s exactly ...", mer);
103 				return;
104 			}
105 			print("O ");
106 		}
107 		numb(m);
108 		print("%s ...", mer);
109 		return;
110 	}
111 	/* hour minute second */
112 	dtsetup(d, &t);
113 	h = t.ifa[3];
114 	m = floor(t.ifa[4]);
115 	s = floor((t.ifa[4]-m) * 60);
116 	print("%.2d:%.2d:%.2d %.*s", h, m, s, utfnlen(t.tz, 3), t.tz);
117 }
118 
119 char*	unit[] =
120 {
121 	"zero",
122 	"one",
123 	"two",
124 	"three",
125 	"four",
126 	"five",
127 	"six",
128 	"seven",
129 	"eight",
130 	"nine",
131 	"ten",
132 	"eleven",
133 	"twelve",
134 	"thirteen",
135 	"fourteen",
136 	"fifteen",
137 	"sixteen",
138 	"seventeen",
139 	"eighteen",
140 	"nineteen"
141 };
142 char*	decade[] =
143 {
144 	"twenty",
145 	"thirty",
146 	"forty",
147 	"fifty",
148 	"sixty",
149 	"seventy",
150 	"eighty",
151 	"ninety"
152 };
153 
154 void
pstime(double d)155 pstime(double d)
156 {
157 
158 	setime(d);
159 
160 	semi = 0;
161 	motion = 0;
162 	rad = 1.e9;
163 	lambda = 0;
164 	beta = 0;
165 
166 // uses lambda, beta, rad, motion
167 // sets alpha, delta, rp
168 
169 	helio();
170 
171 // uses alpha, delta, rp
172 // sets ra, decl, lha, decl2, az, el
173 
174 	geo();
175 
176 	print(" %R %D %D %4.0f", lha, nlat, awlong, elev/3.28084);
177 }
178 
179 void
numb(int n)180 numb(int n)
181 {
182 
183 	if(n >= 100) {
184 		print("%d ", n);
185 		return;
186 	}
187 	if(n >= 20) {
188 		print("%s ", decade[n/10 - 2]);
189 		n %= 10;
190 		if(n == 0)
191 			return;
192 	}
193 	print("%s ", unit[n]);
194 }
195 
196 double
tzone(double y,Tim * z)197 tzone(double y, Tim *z)
198 {
199 	double t, l1, l2;
200 	Tm t1, t2;
201 
202 	/*
203 	 * get a rough approximation to unix mean time
204 	 */
205 	t = (y - 25567.5) * 86400;
206 
207 	/*
208 	 * if outside unix conversions,
209 	 * just call it GMT
210 	 */
211 	if(t < 0 || t > 2.1e9)
212 		return y;
213 
214 	/*
215 	 * convert by both local and gmt
216 	 */
217 	t1 = *localtime((long)t);
218 	t2 = *gmtime((long)t);
219 
220 	/*
221 	 * pick up year crossings
222 	 */
223 	if(t1.yday == 0 && t2.yday > 1)
224 		t1.yday = t2.yday+1;
225 	if(t2.yday == 0 && t1.yday > 1)
226 		t2.yday = t1.yday+1;
227 
228 	/*
229 	 * convert times to days
230 	 */
231 	l1 = t1.yday + t1.hour/24. + t1.min/1440. + t1.sec/86400.;
232 	l2 = t2.yday + t2.hour/24. + t2.min/1440. + t2.sec/86400.;
233 
234 	/*
235 	 * return difference
236 	 */
237 	strncpy(z->tz, t1.zone, sizeof(z->tz));
238 	return y + (l2 - l1);
239 }
240 
241 int	dmo[12] =
242 {
243 	0,
244 	31,
245 	59,
246 	90,
247 	120,
248 	151,
249 	181,
250 	212,
251 	243,
252 	273,
253 	304,
254 	334
255 };
256 
257 /*
258  * input date conversion
259  * output is done by zero crossing
260  * on this input conversion.
261  */
262 double
convdate(Tim * t)263 convdate(Tim *t)
264 {
265 	double y, d;
266 	int m;
267 
268 	y = t->ifa[0];
269 	m = t->ifa[1];
270 	d = t->ifa[2];
271 
272 	/*
273 	 * normalize the month
274 	 */
275 	while(m < 1) {
276 		m += 12;
277 		y -= 1;
278 	}
279 	while(m > 12) {
280 		m -= 12;
281 		y += 1;
282 	}
283 
284 	/*
285 	 * bc correction
286 	 */
287 	if(y < 0)
288 		y += 1;
289 
290 	/*
291 	 * normal conversion
292 	 */
293 	y += 4712;
294 	if(fmod(y, 4) == 0 && m > 2)
295 		d += 1;
296 	y = y*365 + floor((y+3)/4) + dmo[m-1] + d - 1;
297 
298 	/*
299 	 * gregorian change
300 	 */
301 	if(y > 2361232)
302 		y -= floor((y-1794167)/36524.220) -
303 			floor((y-1721117)/146100);
304 	y += t->ifa[3]/24 + t->ifa[4]/1440 - 2415020.5;
305 
306 	/*
307 	 * kitchen clock correction
308 	 */
309 	strncpy(t->tz, "GMT", sizeof(t->tz));
310 	if(flags['k'])
311 		y = tzone(y, t);
312 	return y;
313 }
314