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