]> git.saurik.com Git - apple/icu.git/blob - icuSources/test/intltest/astrotst.cpp
ICU-400.38.tar.gz
[apple/icu.git] / icuSources / test / intltest / astrotst.cpp
1 /********************************************************************
2 * COPYRIGHT:
3 * Copyright (c) 1996-2006, 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 if(!df_t || !df_d || !df_dt) {
281 errln("couldn't create dateformats.");
282 return;
283 }
284 df_t->adoptTimeZone(tz->clone());
285 df_d->adoptTimeZone(tz->clone());
286 df_dt->adoptTimeZone(tz->clone());
287
288 for (int32_t i=0; i < 30; i++) {
289 logln("setDate\n");
290 astro3->setDate(cal->getTime(status));
291 logln("getRiseSet(TRUE)\n");
292 UDate sunrise = astro3->getSunRiseSet(TRUE);
293 logln("getRiseSet(FALSE)\n");
294 UDate sunset = astro3->getSunRiseSet(FALSE);
295 logln("end of getRiseSet\n");
296
297 cal2->setTime(cal->getTime(status), status);
298 cal2->set(UCAL_SECOND, 0);
299 cal2->set(UCAL_MILLISECOND, 0);
300
301 cal2->set(UCAL_HOUR_OF_DAY, USNO[4*i+0]);
302 cal2->set(UCAL_MINUTE, USNO[4*i+1]);
303 UDate exprise = cal2->getTime(status);
304 cal2->set(UCAL_HOUR_OF_DAY, USNO[4*i+2]);
305 cal2->set(UCAL_MINUTE, USNO[4*i+3]);
306 UDate expset = cal2->getTime(status);
307 // Compute delta of what we got to the USNO data, in seconds
308 int32_t deltarise = (int32_t)uprv_fabs((sunrise - exprise) / 1000);
309 int32_t deltaset = (int32_t)uprv_fabs((sunset - expset) / 1000);
310
311 // Allow a deviation of 0..MAX_DEV seconds
312 // It would be nice to get down to 60 seconds, but at this
313 // point that appears to be impossible without a redo of the
314 // algorithm using something more advanced than Duffett-Smith.
315 int32_t MAX_DEV = 180;
316 UnicodeString s1, s2, s3, s4, s5;
317 if (deltarise > MAX_DEV || deltaset > MAX_DEV) {
318 if (deltarise > MAX_DEV) {
319 errln("FAIL: (rise) " + df_d->format(cal->getTime(status),s1) +
320 ", Sunrise: " + df_dt->format(sunrise, s2) +
321 " (USNO " + df_t->format(exprise,s3) +
322 " d=" + deltarise + "s)");
323 } else {
324 logln(df_d->format(cal->getTime(status),s1) +
325 ", Sunrise: " + df_dt->format(sunrise,s2) +
326 " (USNO " + df_t->format(exprise,s3) + ")");
327 }
328 s1.remove(); s2.remove(); s3.remove(); s4.remove(); s5.remove();
329 if (deltaset > MAX_DEV) {
330 errln("FAIL: (set) " + df_d->format(cal->getTime(status),s1) +
331 ", Sunset: " + df_dt->format(sunset,s2) +
332 " (USNO " + df_t->format(expset,s3) +
333 " d=" + deltaset + "s)");
334 } else {
335 logln(df_d->format(cal->getTime(status),s1) +
336 ", Sunset: " + df_dt->format(sunset,s2) +
337 " (USNO " + df_t->format(expset,s3) + ")");
338 }
339 } else {
340 logln(df_d->format(cal->getTime(status),s1) +
341 ", Sunrise: " + df_dt->format(sunrise,s2) +
342 " (USNO " + df_t->format(exprise,s3) + ")" +
343 ", Sunset: " + df_dt->format(sunset,s4) +
344 " (USNO " + df_t->format(expset,s5) + ")");
345 }
346 cal->add(UCAL_DATE, 1, status);
347 }
348
349 // CalendarAstronomer a = new CalendarAstronomer(-(71+5/60), 42+37/60);
350 // cal.clear();
351 // cal.set(cal.YEAR, 1986);
352 // cal.set(cal.MONTH, cal.MARCH);
353 // cal.set(cal.DATE, 10);
354 // cal.set(cal.YEAR, 1988);
355 // cal.set(cal.MONTH, cal.JULY);
356 // cal.set(cal.DATE, 27);
357 // a.setDate(cal.getTime());
358 // long r = a.getSunRiseSet2(true);
359 delete astro3;
360 delete tz;
361 delete cal;
362 delete cal2;
363 delete df_t;
364 delete df_d;
365 delete df_dt;
366 closeAstro(status);
367 ASSERT_OK(status);
368 }
369
370
371
372 void AstroTest::TestBasics(void) {
373 UErrorCode status = U_ZERO_ERROR;
374 initAstro(status);
375 ASSERT_OK(status);
376
377 // Check that our JD computation is the same as the book's (p. 88)
378 GregorianCalendar *cal3 = new GregorianCalendar(TimeZone::getGMT()->clone(), Locale::getUS(), status);
379 DateFormat *d3 = DateFormat::createDateTimeInstance(DateFormat::MEDIUM,DateFormat::MEDIUM,Locale::getUS());
380 d3->setTimeZone(*TimeZone::getGMT());
381 cal3->clear();
382 cal3->set(UCAL_YEAR, 1980);
383 cal3->set(UCAL_MONTH, UCAL_JULY);
384 cal3->set(UCAL_DATE, 2);
385 logln("cal3[a]=%.1lf, d=%d\n", cal3->getTime(status), cal3->get(UCAL_JULIAN_DAY,status));
386 {
387 UnicodeString s;
388 logln(UnicodeString("cal3[a] = ") + d3->format(cal3->getTime(status),s));
389 }
390 cal3->clear();
391 cal3->set(UCAL_YEAR, 1980);
392 cal3->set(UCAL_MONTH, UCAL_JULY);
393 cal3->set(UCAL_DATE, 27);
394 logln("cal3=%.1lf, d=%d\n", cal3->getTime(status), cal3->get(UCAL_JULIAN_DAY,status));
395
396 ASSERT_OK(status);
397 {
398 UnicodeString s;
399 logln(UnicodeString("cal3 = ") + d3->format(cal3->getTime(status),s));
400 }
401 astro->setTime(cal3->getTime(status));
402 double jd = astro->getJulianDay() - 2447891.5;
403 double exp = -3444.;
404 if (jd == exp) {
405 UnicodeString s;
406 logln(d3->format(cal3->getTime(status),s) + " => " + jd);
407 } else {
408 UnicodeString s;
409 errln("FAIL: " + d3->format(cal3->getTime(status), s) + " => " + jd +
410 ", expected " + exp);
411 }
412
413 // cal3.clear();
414 // cal3.set(cal3.YEAR, 1990);
415 // cal3.set(cal3.MONTH, Calendar.JANUARY);
416 // cal3.set(cal3.DATE, 1);
417 // cal3.add(cal3.DATE, -1);
418 // astro.setDate(cal3.getTime());
419 // astro.foo();
420
421 delete cal3;
422 delete d3;
423 ASSERT_OK(status);
424 closeAstro(status);
425 ASSERT_OK(status);
426
427 }
428
429
430 // TODO: try finding next new moon after 07/28/1984 16:00 GMT
431
432
433 #endif
434
435
436