xref: /plan9-contrib/sys/src/cmd/astro/pdate.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
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
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
37 dtsetup(double d, Tim *t)
38 {
39 	double v;
40 
41 	t->ifa[0] = floor(1900 + d/365.2425);
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
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 	/* year month day */
72 	print("%4d %2d %2d",
73 		(int)t.ifa[0],
74 		(int)t.ifa[1],
75 		(int)t.ifa[2]);
76 }
77 
78 void
79 ptime(double d)
80 {
81 	int h, m, s;
82 	char *mer;
83 	Tim t;
84 
85 	if(flags['s']) {
86 		/* hour minute */
87 		dtsetup(d + .5/(24*60), &t);
88 		h = t.ifa[3];
89 		m = floor(t.ifa[4]);
90 
91 		mer = "AM";
92 		if(h >= 12) {
93 			mer = "PM";
94 			h -= 12;
95 		}
96 		if(h == 0)
97 			h = 12;
98 		numb(h);
99 		if(m < 10) {
100 			if(m == 0) {
101 				print("%s exactly ...", mer);
102 				return;
103 			}
104 			print("O ");
105 		}
106 		numb(m);
107 		print("%s ...", mer);
108 		return;
109 	}
110 	/* hour minute second */
111 	dtsetup(d, &t);
112 	h = t.ifa[3];
113 	m = floor(t.ifa[4]);
114 	s = floor((t.ifa[4]-m) * 60);
115 	print("%.2d:%.2d:%.2d %.3s", h, m, s, t.tz);
116 }
117 
118 char*	unit[] =
119 {
120 	"zero",
121 	"one",
122 	"two",
123 	"three",
124 	"four",
125 	"five",
126 	"six",
127 	"seven",
128 	"eight",
129 	"nine",
130 	"ten",
131 	"eleven",
132 	"twelve",
133 	"thirteen",
134 	"fourteen",
135 	"fifteen",
136 	"sixteen",
137 	"seventeen",
138 	"eighteen",
139 	"nineteen"
140 };
141 char*	decade[] =
142 {
143 	"twenty",
144 	"thirty",
145 	"forty",
146 	"fifty",
147 	"sixty",
148 	"seventy",
149 	"eighty",
150 	"ninety"
151 };
152 
153 void
154 numb(int n)
155 {
156 
157 	if(n >= 100) {
158 		print("%l ", n);
159 		return;
160 	}
161 	if(n >= 20) {
162 		print("%s ", decade[n/10 - 2]);
163 		n %= 10;
164 		if(n == 0)
165 			return;
166 	}
167 	print("%s ", unit[n]);
168 }
169 
170 double
171 tzone(double y, Tim *z)
172 {
173 	double t, l1, l2;
174 	Tm t1, t2;
175 
176 	/*
177 	 * get a rough approximation to unix mean time
178 	 */
179 	t = (y - 25567.5) * 86400;
180 
181 	/*
182 	 * if outside unix conversions,
183 	 * just call it GMT
184 	 */
185 	if(t < 0 || t > 2.1e9)
186 		return y;
187 
188 	/*
189 	 * convert by both local and gmt
190 	 */
191 	t1 = *localtime((long)t);
192 	t2 = *gmtime((long)t);
193 
194 	/*
195 	 * pick up year crossings
196 	 */
197 	if(t1.yday == 0 && t2.yday > 1)
198 		t1.yday = t2.yday+1;
199 	if(t2.yday == 0 && t1.yday > 1)
200 		t2.yday = t1.yday+1;
201 
202 	/*
203 	 * convert times to days
204 	 */
205 	l1 = t1.yday + t1.hour/24. + t1.min/1440. + t1.sec/86400.;
206 	l2 = t2.yday + t2.hour/24. + t2.min/1440. + t2.sec/86400.;
207 
208 	/*
209 	 * return difference
210 	 */
211 	strncpy(z->tz, t1.zone, sizeof(z->tz));
212 	return y + (l2 - l1);
213 }
214 
215 int	dmo[12] =
216 {
217 	0,
218 	31,
219 	59,
220 	90,
221 	120,
222 	151,
223 	181,
224 	212,
225 	243,
226 	273,
227 	304,
228 	334
229 };
230 
231 /*
232  * input date conversion
233  * output is done by zero crossing
234  * on this input conversion.
235  */
236 double
237 convdate(Tim *t)
238 {
239 	double y, d;
240 	int m;
241 
242 	y = t->ifa[0];
243 	m = t->ifa[1];
244 	d = t->ifa[2];
245 
246 	/*
247 	 * normalize the month
248 	 */
249 	while(m < 1) {
250 		m += 12;
251 		y -= 1;
252 	}
253 	while(m > 12) {
254 		m -= 12;
255 		y += 1;
256 	}
257 
258 	/*
259 	 * bc correction
260 	 */
261 	if(y < 0)
262 		y += 1;
263 
264 	/*
265 	 * normal conversion
266 	 */
267 	y += 4712;
268 	if(fmod(y, 4) == 0 && m > 2)
269 		d += 1;
270 	y = y*365 + floor((y+3)/4) + dmo[m-1] + d - 1;
271 
272 	/*
273 	 * gregorian change
274 	 */
275 	if(y > 2361232)
276 		y -= floor((y-1794167)/36525) -
277 			floor((y-1721117)/146100);
278 	y += t->ifa[3]/24 + t->ifa[4]/1440 - 2415020.5;
279 
280 	/*
281 	 * kitchen clock correction
282 	 */
283 	strncpy(t->tz, "GMT", sizeof(t->tz));
284 	if(flags['k'])
285 		y = tzone(y, t);
286 	return y;
287 }
288