]>
git.saurik.com Git - apple/icu.git/blob - icuSources/test/intltest/astrotst.cpp
1 /********************************************************************
3 * Copyright (c) 1996-2004, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ********************************************************************/
7 /* Test CalendarAstronomer for C++ */
9 #include "unicode/utypes.h"
11 #include "unicode/locid.h"
13 #if !UCONFIG_NO_FORMATTING
17 #include "gregoimp.h" // for Math
18 #include "unicode/simpletz.h"
21 static const double DAY_MS
= 24.*60.*60.*1000.;
23 #define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break
25 AstroTest::AstroTest(): astro(NULL
), gc(NULL
) {
28 void AstroTest::runIndexedTest( int32_t index
, UBool exec
, const char* &name
, char* /*par*/ )
30 if (exec
) logln("TestSuite AstroTest");
33 CASE(0,TestSolarLongitude
);
34 CASE(1,TestLunarPosition
);
35 CASE(2,TestCoordinates
);
37 CASE(4,TestSunriseTimes
);
39 default: name
= ""; break;
45 #define ASSERT_OK(x) if(U_FAILURE(x)) { errln("%s:%d: %s\n", __FILE__, __LINE__, u_errorName(x)); return; }
48 void AstroTest::initAstro(UErrorCode
&status
) {
49 if(U_FAILURE(status
)) return;
51 if((astro
!= NULL
) || (gc
!= NULL
)) {
52 errln("Err: initAstro() called twice!");
54 if(U_SUCCESS(status
)) {
55 status
= U_INTERNAL_PROGRAM_ERROR
;
59 if(U_FAILURE(status
)) return;
61 astro
= new CalendarAstronomer();
62 gc
= Calendar::createInstance(TimeZone::getGMT()->clone(), status
);
65 void AstroTest::closeAstro(UErrorCode
&/*status*/) {
76 void AstroTest::TestSolarLongitude(void) {
77 UErrorCode status
= U_ZERO_ERROR
;
82 int32_t d
[5]; double f
;
84 { { 1980, 7, 27, 0, 00 }, 124.114347 },
85 { { 1988, 7, 27, 00, 00 }, 124.187732 }
89 for (uint32_t i
= 0; i
< sizeof(tests
)/sizeof(tests
[0]); i
++) {
91 gc
->set(tests
[i
].d
[0], tests
[i
].d
[1]-1, tests
[i
].d
[2], tests
[i
].d
[3], tests
[i
].d
[4]);
93 astro
->setDate(gc
->getTime(status
));
95 double longitude
= astro
->getSunLongitude();
97 CalendarAstronomer::Equatorial result
;
98 astro
->getSunPosition(result
);
99 logln((UnicodeString
)"Sun position is " + result
.toString() + (UnicodeString
)"; " /* + result.toHmsString()*/ + " Sun longitude is " + longitude
);
107 void AstroTest::TestLunarPosition(void) {
108 UErrorCode status
= U_ZERO_ERROR
;
112 static const double tests
[][7] = {
113 { 1979, 2, 26, 16, 00, 0, 0 }
117 for (int32_t i
= 0; i
< (int32_t)(sizeof(tests
)/sizeof(tests
[0])); i
++) {
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
));
122 const CalendarAstronomer::Equatorial
& result
= astro
->getMoonPosition();
123 logln((UnicodeString
)"Moon position is " + result
.toString() + (UnicodeString
)"; " /* + result->toHmsString()*/);
132 void AstroTest::TestCoordinates(void) {
133 UErrorCode status
= U_ZERO_ERROR
;
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()*/ );
146 void AstroTest::TestCoverage(void) {
147 UErrorCode status
= U_ZERO_ERROR
;
150 GregorianCalendar
*cal
= new GregorianCalendar(1958, UCAL_AUGUST
, 15,status
);
151 UDate then
= cal
->getTime(status
);
152 CalendarAstronomer
*myastro
= new CalendarAstronomer(then
);
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
);
160 double eclLat
= laLat
* CalendarAstronomer::PI
/ 360;
161 double eclLong
= laLong
* CalendarAstronomer::PI
/ 360;
163 CalendarAstronomer::Ecliptic
ecl(eclLat
, eclLong
);
164 CalendarAstronomer::Equatorial eq
;
165 CalendarAstronomer::Horizon hor
;
167 logln("ecliptic: " + ecl
.toString());
168 CalendarAstronomer
*myastro3
= new CalendarAstronomer();
169 myastro3
->setJulianDay((4713 + 2000) * 365.25);
171 CalendarAstronomer
*astronomers
[] = {
172 myastro
, myastro2
, myastro3
, myastro2
// check cache
175 for (uint32_t i
= 0; i
< sizeof(astronomers
)/sizeof(astronomers
[0]); ++i
) {
176 CalendarAstronomer
*anAstro
= astronomers
[i
];
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
)));
208 void AstroTest::TestSunriseTimes(void) {
209 UErrorCode status
= U_ZERO_ERROR
;
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");
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
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);
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).
266 // TimeZone tz = TimeZone.getTimeZone("America/Montreal");
267 TimeZone
*tz
= new SimpleTimeZone(-18000000 + 3600000, "Montreal(FIXED)");
269 GregorianCalendar
*cal
= new GregorianCalendar(tz
->clone(), Locale::getUS(), status
);
270 GregorianCalendar
*cal2
= new GregorianCalendar(tz
->clone(), Locale::getUS(), status
);
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
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());
284 for (int32_t i
=0; i
< 30; i
++) {
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");
293 cal2
->setTime(cal
->getTime(status
), status
);
294 cal2
->set(UCAL_SECOND
, 0);
295 cal2
->set(UCAL_MILLISECOND
, 0);
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);
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)");
320 logln(df_d
->format(cal
->getTime(status
),s1
) +
321 ", Sunrise: " + df_dt
->format(sunrise
,s2
) +
322 " (USNO " + df_t
->format(exprise
,s3
) + ")");
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)");
331 logln(df_d
->format(cal
->getTime(status
),s1
) +
332 ", Sunset: " + df_dt
->format(sunset
,s2
) +
333 " (USNO " + df_t
->format(expset
,s3
) + ")");
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
) + ")");
342 cal
->add(UCAL_DATE
, 1, status
);
345 // CalendarAstronomer a = new CalendarAstronomer(-(71+5/60), 42+37/60);
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);
368 void AstroTest::TestBasics(void) {
369 UErrorCode status
= U_ZERO_ERROR
;
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());
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
));
384 logln(UnicodeString("cal3[a] = ") + d3
->format(cal3
->getTime(status
),s
));
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
));
395 logln(UnicodeString("cal3 = ") + d3
->format(cal3
->getTime(status
),s
));
397 astro
->setTime(cal3
->getTime(status
));
398 double jd
= astro
->getJulianDay() - 2447891.5;
402 logln(d3
->format(cal3
->getTime(status
),s
) + " => " + jd
);
405 errln("FAIL: " + d3
->format(cal3
->getTime(status
), s
) + " => " + jd
+
406 ", expected " + exp
);
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());
426 // TODO: try finding next new moon after 07/28/1984 16:00 GMT