]> git.saurik.com Git - apple/icu.git/blob - icuSources/test/intltest/astrotst.cpp
ICU-6.2.4.tar.gz
[apple/icu.git] / icuSources / test / intltest / astrotst.cpp
1 /********************************************************************
2 * COPYRIGHT:
3 * Copyright (c) 1996-2004, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ********************************************************************/
6
7 /* Test CalendarAstronomer for C++ */
8
9 #include "unicode/utypes.h"
10 #include "string.h"
11 #include "unicode/locid.h"
12
13 #if !UCONFIG_NO_FORMATTING
14
15 #include "astro.h"
16 #include "astrotst.h"
17 #include "gregoimp.h" // for Math
18 #include "unicode/simpletz.h"
19
20
21 static const double DAY_MS = 24.*60.*60.*1000.;
22
23 #define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break
24
25 AstroTest::AstroTest(): astro(NULL), gc(NULL) {
26 }
27
28 void AstroTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
29 {
30 if (exec) logln("TestSuite AstroTest");
31 switch (index) {
32 // CASE(0,FooTest);
33 CASE(0,TestSolarLongitude);
34 CASE(1,TestLunarPosition);
35 CASE(2,TestCoordinates);
36 CASE(3,TestCoverage);
37 CASE(4,TestSunriseTimes);
38 CASE(5,TestBasics);
39 default: name = ""; break;
40 }
41 }
42
43 #undef CASE
44
45 #define ASSERT_OK(x) if(U_FAILURE(x)) { errln("%s:%d: %s\n", __FILE__, __LINE__, u_errorName(x)); return; }
46
47
48 void AstroTest::initAstro(UErrorCode &status) {
49 if(U_FAILURE(status)) return;
50
51 if((astro != NULL) || (gc != NULL)) {
52 errln("Err: initAstro() called twice!");
53 closeAstro(status);
54 if(U_SUCCESS(status)) {
55 status = U_INTERNAL_PROGRAM_ERROR;
56 }
57 }
58
59 if(U_FAILURE(status)) return;
60
61 astro = new CalendarAstronomer();
62 gc = Calendar::createInstance(TimeZone::getGMT()->clone(), status);
63 }
64
65 void AstroTest::closeAstro(UErrorCode &/*status*/) {
66 if(astro != NULL) {
67 delete astro;
68 astro = NULL;
69 }
70 if(gc != NULL) {
71 delete gc;
72 gc = NULL;
73 }
74 }
75
76 void AstroTest::TestSolarLongitude(void) {
77 UErrorCode status = U_ZERO_ERROR;
78 initAstro(status);
79 ASSERT_OK(status);
80
81 struct {
82 int32_t d[5]; double f ;
83 } tests[] = {
84 { { 1980, 7, 27, 0, 00 }, 124.114347 },
85 { { 1988, 7, 27, 00, 00 }, 124.187732 }
86 };
87
88 logln("");
89 for (uint32_t i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) {
90 gc->clear();
91 gc->set(tests[i].d[0], tests[i].d[1]-1, tests[i].d[2], tests[i].d[3], tests[i].d[4]);
92
93 astro->setDate(gc->getTime(status));
94
95 double longitude = astro->getSunLongitude();
96 //longitude = 0;
97 CalendarAstronomer::Equatorial result;
98 astro->getSunPosition(result);
99 logln((UnicodeString)"Sun position is " + result.toString() + (UnicodeString)"; " /* + result.toHmsString()*/ + " Sun longitude is " + longitude );
100 }
101 closeAstro(status);
102 ASSERT_OK(status);
103 }
104
105
106
107 void AstroTest::TestLunarPosition(void) {
108 UErrorCode status = U_ZERO_ERROR;
109 initAstro(status);
110 ASSERT_OK(status);
111
112 static const double tests[][7] = {
113 { 1979, 2, 26, 16, 00, 0, 0 }
114 };
115 logln("");
116
117 for (int32_t i = 0; i < (int32_t)(sizeof(tests)/sizeof(tests[0])); i++) {
118 gc->clear();
119 gc->set((int32_t)tests[i][0], (int32_t)tests[i][1]-1, (int32_t)tests[i][2], (int32_t)tests[i][3], (int32_t)tests[i][4]);
120 astro->setDate(gc->getTime(status));
121
122 const CalendarAstronomer::Equatorial& result = astro->getMoonPosition();
123 logln((UnicodeString)"Moon position is " + result.toString() + (UnicodeString)"; " /* + result->toHmsString()*/);
124 }
125
126 closeAstro(status);
127 ASSERT_OK(status);
128 }
129
130
131
132 void AstroTest::TestCoordinates(void) {
133 UErrorCode status = U_ZERO_ERROR;
134 initAstro(status);
135 ASSERT_OK(status);
136
137 CalendarAstronomer::Equatorial result;
138 astro->eclipticToEquatorial(result, 139.686111 * CalendarAstronomer::PI / 180.0, 4.875278* CalendarAstronomer::PI / 180.0);
139 logln((UnicodeString)"result is " + result.toString() + (UnicodeString)"; " /* + result.toHmsString()*/ );
140 closeAstro(status);
141 ASSERT_OK(status);
142 }
143
144
145
146 void AstroTest::TestCoverage(void) {
147 UErrorCode status = U_ZERO_ERROR;
148 initAstro(status);
149 ASSERT_OK(status);
150 GregorianCalendar *cal = new GregorianCalendar(1958, UCAL_AUGUST, 15,status);
151 UDate then = cal->getTime(status);
152 CalendarAstronomer *myastro = new CalendarAstronomer(then);
153 ASSERT_OK(status);
154
155 //Latitude: 34 degrees 05' North
156 //Longitude: 118 degrees 22' West
157 double laLat = 34 + 5./60, laLong = 360 - (118 + 22./60);
158 CalendarAstronomer *myastro2 = new CalendarAstronomer(laLong, laLat);
159
160 double eclLat = laLat * CalendarAstronomer::PI / 360;
161 double eclLong = laLong * CalendarAstronomer::PI / 360;
162
163 CalendarAstronomer::Ecliptic ecl(eclLat, eclLong);
164 CalendarAstronomer::Equatorial eq;
165 CalendarAstronomer::Horizon hor;
166
167 logln("ecliptic: " + ecl.toString());
168 CalendarAstronomer *myastro3 = new CalendarAstronomer();
169 myastro3->setJulianDay((4713 + 2000) * 365.25);
170
171 CalendarAstronomer *astronomers[] = {
172 myastro, myastro2, myastro3, myastro2 // check cache
173 };
174
175 for (uint32_t i = 0; i < sizeof(astronomers)/sizeof(astronomers[0]); ++i) {
176 CalendarAstronomer *anAstro = astronomers[i];
177
178 //logln("astro: " + astro);
179 logln((UnicodeString)" date: " + anAstro->getTime());
180 logln((UnicodeString)" cent: " + anAstro->getJulianCentury());
181 logln((UnicodeString)" gw sidereal: " + anAstro->getGreenwichSidereal());
182 logln((UnicodeString)" loc sidereal: " + anAstro->getLocalSidereal());
183 logln((UnicodeString)" equ ecl: " + (anAstro->eclipticToEquatorial(eq,ecl)).toString());
184 logln((UnicodeString)" equ long: " + (anAstro->eclipticToEquatorial(eq, eclLong)).toString());
185 logln((UnicodeString)" horiz: " + (anAstro->eclipticToHorizon(hor, eclLong)).toString());
186 logln((UnicodeString)" sunrise: " + (anAstro->getSunRiseSet(TRUE)));
187 logln((UnicodeString)" sunset: " + (anAstro->getSunRiseSet(FALSE)));
188 logln((UnicodeString)" moon phase: " + anAstro->getMoonPhase());
189 logln((UnicodeString)" moonrise: " + (anAstro->getMoonRiseSet(TRUE)));
190 logln((UnicodeString)" moonset: " + (anAstro->getMoonRiseSet(FALSE)));
191 logln((UnicodeString)" prev summer solstice: " + (anAstro->getSunTime(CalendarAstronomer::SUMMER_SOLSTICE(), FALSE)));
192 logln((UnicodeString)" next summer solstice: " + (anAstro->getSunTime(CalendarAstronomer::SUMMER_SOLSTICE(), TRUE)));
193 logln((UnicodeString)" prev full moon: " + (anAstro->getMoonTime(CalendarAstronomer::FULL_MOON(), FALSE)));
194 logln((UnicodeString)" next full moon: " + (anAstro->getMoonTime(CalendarAstronomer::FULL_MOON(), TRUE)));
195 }
196
197 delete myastro2;
198 delete myastro3;
199 delete myastro;
200 delete cal;
201
202 closeAstro(status);
203 ASSERT_OK(status);
204 }
205
206
207
208 void AstroTest::TestSunriseTimes(void) {
209 UErrorCode status = U_ZERO_ERROR;
210 initAstro(status);
211 ASSERT_OK(status);
212
213 // logln("Sunrise/Sunset times for San Jose, California, USA");
214 // CalendarAstronomer *astro2 = new CalendarAstronomer(-121.55, 37.20);
215 // TimeZone *tz = TimeZone::createTimeZone("America/Los_Angeles");
216
217 // We'll use a table generated by the UNSO website as our reference
218 // From: http://aa.usno.navy.mil/
219 //-Location: W079 25, N43 40
220 //-Rise and Set for the Sun for 2001
221 //-Zone: 4h West of Greenwich
222 int32_t USNO[] = {
223 6,59, 19,45,
224 6,57, 19,46,
225 6,56, 19,47,
226 6,54, 19,48,
227 6,52, 19,49,
228 6,50, 19,51,
229 6,48, 19,52,
230 6,47, 19,53,
231 6,45, 19,54,
232 6,43, 19,55,
233 6,42, 19,57,
234 6,40, 19,58,
235 6,38, 19,59,
236 6,36, 20, 0,
237 6,35, 20, 1,
238 6,33, 20, 3,
239 6,31, 20, 4,
240 6,30, 20, 5,
241 6,28, 20, 6,
242 6,27, 20, 7,
243 6,25, 20, 8,
244 6,23, 20,10,
245 6,22, 20,11,
246 6,20, 20,12,
247 6,19, 20,13,
248 6,17, 20,14,
249 6,16, 20,16,
250 6,14, 20,17,
251 6,13, 20,18,
252 6,11, 20,19,
253 };
254
255 logln("Sunrise/Sunset times for Toronto, Canada");
256 // long = 79 25", lat = 43 40"
257 CalendarAstronomer *astro3 = new CalendarAstronomer(-(79+25/60), 43+40/60);
258
259 // As of ICU4J 2.8 the ICU4J time zones implement pass-through
260 // to the underlying JDK. Because of variation in the
261 // underlying JDKs, we have to use a fixed-offset
262 // SimpleTimeZone to get consistent behavior between JDKs.
263 // The offset we want is [-18000000, 3600000] (raw, dst).
264 // [aliu 10/15/03]
265
266 // TimeZone tz = TimeZone.getTimeZone("America/Montreal");
267 TimeZone *tz = new SimpleTimeZone(-18000000 + 3600000, "Montreal(FIXED)");
268
269 GregorianCalendar *cal = new GregorianCalendar(tz->clone(), Locale::getUS(), status);
270 GregorianCalendar *cal2 = new GregorianCalendar(tz->clone(), Locale::getUS(), status);
271 cal->clear();
272 cal->set(UCAL_YEAR, 2001);
273 cal->set(UCAL_MONTH, UCAL_APRIL);
274 cal->set(UCAL_DAY_OF_MONTH, 1);
275 cal->set(UCAL_HOUR_OF_DAY, 12); // must be near local noon for getSunRiseSet to work
276
277 DateFormat *df_t = DateFormat::createTimeInstance(DateFormat::MEDIUM,Locale::getUS());
278 DateFormat *df_d = DateFormat::createDateInstance(DateFormat::MEDIUM,Locale::getUS());
279 DateFormat *df_dt = DateFormat::createDateTimeInstance(DateFormat::MEDIUM, DateFormat::MEDIUM, Locale::getUS());
280 df_t->adoptTimeZone(tz->clone());
281 df_d->adoptTimeZone(tz->clone());
282 df_dt->adoptTimeZone(tz->clone());
283
284 for (int32_t i=0; i < 30; i++) {
285 logln("setDate\n");
286 astro3->setDate(cal->getTime(status));
287 logln("getRiseSet(TRUE)\n");
288 UDate sunrise = astro3->getSunRiseSet(TRUE);
289 logln("getRiseSet(FALSE)\n");
290 UDate sunset = astro3->getSunRiseSet(FALSE);
291 logln("end of getRiseSet\n");
292
293 cal2->setTime(cal->getTime(status), status);
294 cal2->set(UCAL_SECOND, 0);
295 cal2->set(UCAL_MILLISECOND, 0);
296
297 cal2->set(UCAL_HOUR_OF_DAY, USNO[4*i+0]);
298 cal2->set(UCAL_MINUTE, USNO[4*i+1]);
299 UDate exprise = cal2->getTime(status);
300 cal2->set(UCAL_HOUR_OF_DAY, USNO[4*i+2]);
301 cal2->set(UCAL_MINUTE, USNO[4*i+3]);
302 UDate expset = cal2->getTime(status);
303 // Compute delta of what we got to the USNO data, in seconds
304 int32_t deltarise = (int32_t)uprv_fabs((sunrise - exprise) / 1000);
305 int32_t deltaset = (int32_t)uprv_fabs((sunset - expset) / 1000);
306
307 // Allow a deviation of 0..MAX_DEV seconds
308 // It would be nice to get down to 60 seconds, but at this
309 // point that appears to be impossible without a redo of the
310 // algorithm using something more advanced than Duffett-Smith.
311 int32_t MAX_DEV = 180;
312 UnicodeString s1, s2, s3, s4, s5;
313 if (deltarise > MAX_DEV || deltaset > MAX_DEV) {
314 if (deltarise > MAX_DEV) {
315 errln("FAIL: (rise) " + df_d->format(cal->getTime(status),s1) +
316 ", Sunrise: " + df_dt->format(sunrise, s2) +
317 " (USNO " + df_t->format(exprise,s3) +
318 " d=" + deltarise + "s)");
319 } else {
320 logln(df_d->format(cal->getTime(status),s1) +
321 ", Sunrise: " + df_dt->format(sunrise,s2) +
322 " (USNO " + df_t->format(exprise,s3) + ")");
323 }
324 s1.remove(); s2.remove(); s3.remove(); s4.remove(); s5.remove();
325 if (deltaset > MAX_DEV) {
326 errln("FAIL: (set) " + df_d->format(cal->getTime(status),s1) +
327 ", Sunset: " + df_dt->format(sunset,s2) +
328 " (USNO " + df_t->format(expset,s3) +
329 " d=" + deltaset + "s)");
330 } else {
331 logln(df_d->format(cal->getTime(status),s1) +
332 ", Sunset: " + df_dt->format(sunset,s2) +
333 " (USNO " + df_t->format(expset,s3) + ")");
334 }
335 } else {
336 logln(df_d->format(cal->getTime(status),s1) +
337 ", Sunrise: " + df_dt->format(sunrise,s2) +
338 " (USNO " + df_t->format(exprise,s3) + ")" +
339 ", Sunset: " + df_dt->format(sunset,s4) +
340 " (USNO " + df_t->format(expset,s5) + ")");
341 }
342 cal->add(UCAL_DATE, 1, status);
343 }
344
345 // CalendarAstronomer a = new CalendarAstronomer(-(71+5/60), 42+37/60);
346 // cal.clear();
347 // cal.set(cal.YEAR, 1986);
348 // cal.set(cal.MONTH, cal.MARCH);
349 // cal.set(cal.DATE, 10);
350 // cal.set(cal.YEAR, 1988);
351 // cal.set(cal.MONTH, cal.JULY);
352 // cal.set(cal.DATE, 27);
353 // a.setDate(cal.getTime());
354 // long r = a.getSunRiseSet2(true);
355 delete astro3;
356 delete tz;
357 delete cal;
358 delete cal2;
359 delete df_t;
360 delete df_d;
361 delete df_dt;
362 closeAstro(status);
363 ASSERT_OK(status);
364 }
365
366
367
368 void AstroTest::TestBasics(void) {
369 UErrorCode status = U_ZERO_ERROR;
370 initAstro(status);
371 ASSERT_OK(status);
372
373 // Check that our JD computation is the same as the book's (p. 88)
374 GregorianCalendar *cal3 = new GregorianCalendar(TimeZone::getGMT()->clone(), Locale::getUS(), status);
375 DateFormat *d3 = DateFormat::createDateTimeInstance(DateFormat::MEDIUM,DateFormat::MEDIUM,Locale::getUS());
376 d3->setTimeZone(*TimeZone::getGMT());
377 cal3->clear();
378 cal3->set(UCAL_YEAR, 1980);
379 cal3->set(UCAL_MONTH, UCAL_JULY);
380 cal3->set(UCAL_DATE, 2);
381 logln("cal3[a]=%.1lf, d=%d\n", cal3->getTime(status), cal3->get(UCAL_JULIAN_DAY,status));
382 {
383 UnicodeString s;
384 logln(UnicodeString("cal3[a] = ") + d3->format(cal3->getTime(status),s));
385 }
386 cal3->clear();
387 cal3->set(UCAL_YEAR, 1980);
388 cal3->set(UCAL_MONTH, UCAL_JULY);
389 cal3->set(UCAL_DATE, 27);
390 logln("cal3=%.1lf, d=%d\n", cal3->getTime(status), cal3->get(UCAL_JULIAN_DAY,status));
391
392 ASSERT_OK(status);
393 {
394 UnicodeString s;
395 logln(UnicodeString("cal3 = ") + d3->format(cal3->getTime(status),s));
396 }
397 astro->setTime(cal3->getTime(status));
398 double jd = astro->getJulianDay() - 2447891.5;
399 double exp = -3444.;
400 if (jd == exp) {
401 UnicodeString s;
402 logln(d3->format(cal3->getTime(status),s) + " => " + jd);
403 } else {
404 UnicodeString s;
405 errln("FAIL: " + d3->format(cal3->getTime(status), s) + " => " + jd +
406 ", expected " + exp);
407 }
408
409 // cal3.clear();
410 // cal3.set(cal3.YEAR, 1990);
411 // cal3.set(cal3.MONTH, Calendar.JANUARY);
412 // cal3.set(cal3.DATE, 1);
413 // cal3.add(cal3.DATE, -1);
414 // astro.setDate(cal3.getTime());
415 // astro.foo();
416
417 delete cal3;
418 delete d3;
419 ASSERT_OK(status);
420 closeAstro(status);
421 ASSERT_OK(status);
422
423 }
424
425
426 // TODO: try finding next new moon after 07/28/1984 16:00 GMT
427
428
429 #endif
430
431
432