2 *******************************************************************************
\r
3 * Copyright (C) 1996-2010, International Business Machines Corporation and *
\r
4 * others. All Rights Reserved. *
\r
5 *******************************************************************************
\r
7 package com.ibm.icu.dev.test.calendar;
\r
11 import java.util.Date;
\r
12 import java.util.Locale;
\r
14 import com.ibm.icu.dev.test.TestFmwk;
\r
15 import com.ibm.icu.impl.CalendarAstronomer;
\r
16 import com.ibm.icu.impl.CalendarAstronomer.Ecliptic;
\r
17 import com.ibm.icu.impl.CalendarAstronomer.Equatorial;
\r
18 import com.ibm.icu.text.DateFormat;
\r
19 import com.ibm.icu.util.Calendar;
\r
20 import com.ibm.icu.util.GregorianCalendar;
\r
21 import com.ibm.icu.util.SimpleTimeZone;
\r
22 import com.ibm.icu.util.TimeZone;
\r
24 // TODO: try finding next new moon after 07/28/1984 16:00 GMT
\r
26 public class AstroTest extends TestFmwk {
\r
27 public static void main(String[] args) throws Exception {
\r
28 new AstroTest().run(args);
\r
31 static final double PI = Math.PI;
\r
33 public void TestSolarLongitude() {
\r
34 GregorianCalendar gc = new GregorianCalendar(new SimpleTimeZone(0, "UTC"));
\r
35 CalendarAstronomer astro = new CalendarAstronomer();
\r
36 // year, month, day, hour, minute, longitude (radians), ascension(radians), declination(radians)
\r
37 final double tests[][] = {
\r
38 { 1980, 7, 27, 00, 00, 2.166442986535465, 2.2070499713207730, 0.3355704075759270 },
\r
39 { 1988, 7, 27, 00, 00, 2.167484927693959, 2.2081183335606176, 0.3353093444275315 },
\r
42 for (int i = 0; i < tests.length; i++) {
\r
44 gc.set((int)tests[i][0], (int)tests[i][1]-1, (int)tests[i][2], (int)tests[i][3], (int) tests[i][4]);
\r
46 astro.setDate(gc.getTime());
\r
48 double longitude = astro.getSunLongitude();
\r
49 if (longitude != tests[i][5]) {
\r
50 if ((float)longitude == (float)tests[i][5]) {
\r
51 logln("longitude(" + longitude +
\r
52 ") != tests[i][5](" + tests[i][5] +
\r
53 ") in double for test " + i);
\r
55 errln("FAIL: longitude(" + longitude +
\r
56 ") != tests[i][5](" + tests[i][5] +
\r
60 Equatorial result = astro.getSunPosition();
\r
61 if (result.ascension != tests[i][6]) {
\r
62 if ((float)result.ascension == (float)tests[i][6]) {
\r
63 logln("result.ascension(" + result.ascension +
\r
64 ") != tests[i][6](" + tests[i][6] +
\r
65 ") in double for test " + i);
\r
67 errln("FAIL: result.ascension(" + result.ascension +
\r
68 ") != tests[i][6](" + tests[i][6] +
\r
72 if (result.declination != tests[i][7]) {
\r
73 if ((float)result.declination == (float)tests[i][7]) {
\r
74 logln("result.declination(" + result.declination +
\r
75 ") != tests[i][7](" + tests[i][7] +
\r
76 ") in double for test " + i);
\r
78 errln("FAIL: result.declination(" + result.declination +
\r
79 ") != tests[i][7](" + tests[i][7] +
\r
86 public void TestLunarPosition() {
\r
87 GregorianCalendar gc = new GregorianCalendar(new SimpleTimeZone(0, "UTC"));
\r
88 CalendarAstronomer astro = new CalendarAstronomer();
\r
89 // year, month, day, hour, minute, ascension(radians), declination(radians)
\r
90 final double tests[][] = {
\r
91 { 1979, 2, 26, 16, 00, -0.3778379118188744, -0.1399698825594198 },
\r
95 for (int i = 0; i < tests.length; i++) {
\r
97 gc.set((int)tests[i][0], (int)tests[i][1]-1, (int)tests[i][2], (int)tests[i][3], (int) tests[i][4]);
\r
98 astro.setDate(gc.getTime());
\r
100 Equatorial result = astro.getMoonPosition();
\r
101 if (result.ascension != tests[i][5]) {
\r
102 if ((float)result.ascension == (float)tests[i][5]) {
\r
103 logln("result.ascension(" + result.ascension +
\r
104 ") != tests[i][5](" + tests[i][5] +
\r
105 ") in double for test " + i);
\r
107 errln("FAIL: result.ascension(" + result.ascension +
\r
108 ") != tests[i][5](" + tests[i][5] +
\r
109 ") for test " + i);
\r
112 if (result.declination != tests[i][6]) {
\r
113 if ((float)result.declination == (float)tests[i][6]) {
\r
114 logln("result.declination(" + result.declination +
\r
115 ") != tests[i][6](" + tests[i][6] +
\r
116 ") in double for test " + i);
\r
118 errln("FAIL: result.declination(" + result.declination +
\r
119 ") != tests[i][6](" + tests[i][6] +
\r
120 ") for test " + i);
\r
126 public void TestCoordinates() {
\r
127 CalendarAstronomer astro = new CalendarAstronomer();
\r
128 Equatorial result = astro.eclipticToEquatorial(139.686111 * PI/ 180.0, 4.875278* PI / 180.0);
\r
129 logln("result is " + result + "; " + result.toHmsString());
\r
132 public void TestCoverage() {
\r
133 GregorianCalendar cal = new GregorianCalendar(1958, Calendar.AUGUST, 15);
\r
134 Date then = cal.getTime();
\r
135 CalendarAstronomer myastro = new CalendarAstronomer(then);
\r
137 //Latitude: 34 degrees 05' North
\r
138 //Longitude: 118 degrees 22' West
\r
139 double laLat = 34 + 5d/60, laLong = 360 - (118 + 22d/60);
\r
140 CalendarAstronomer myastro2 = new CalendarAstronomer(laLong, laLat);
\r
142 double eclLat = laLat * Math.PI / 360;
\r
143 double eclLong = laLong * Math.PI / 360;
\r
144 Ecliptic ecl = new Ecliptic(eclLat, eclLong);
\r
145 logln("ecliptic: " + ecl);
\r
147 CalendarAstronomer myastro3 = new CalendarAstronomer();
\r
148 myastro3.setJulianDay((4713 + 2000) * 365.25);
\r
150 CalendarAstronomer[] astronomers = {
\r
151 myastro, myastro2, myastro3, myastro2 // check cache
\r
155 for (int i = 0; i < astronomers.length; ++i) {
\r
156 CalendarAstronomer astro = astronomers[i];
\r
158 logln("astro: " + astro);
\r
159 logln(" time: " + astro.getTime());
\r
160 logln(" date: " + astro.getDate());
\r
161 logln(" cent: " + astro.getJulianCentury());
\r
162 logln(" gw sidereal: " + astro.getGreenwichSidereal());
\r
163 logln(" loc sidereal: " + astro.getLocalSidereal());
\r
164 logln(" equ ecl: " + astro.eclipticToEquatorial(ecl));
\r
165 logln(" equ long: " + astro.eclipticToEquatorial(eclLong));
\r
166 logln(" horiz: " + astro.eclipticToHorizon(eclLong));
\r
167 logln(" sunrise: " + new Date(astro.getSunRiseSet(true)));
\r
168 logln(" sunset: " + new Date(astro.getSunRiseSet(false)));
\r
169 logln(" moon phase: " + astro.getMoonPhase());
\r
170 logln(" moonrise: " + new Date(astro.getMoonRiseSet(true)));
\r
171 logln(" moonset: " + new Date(astro.getMoonRiseSet(false)));
\r
172 logln(" prev summer solstice: " + new Date(astro.getSunTime(CalendarAstronomer.SUMMER_SOLSTICE, false)));
\r
173 logln(" next summer solstice: " + new Date(astro.getSunTime(CalendarAstronomer.SUMMER_SOLSTICE, true)));
\r
174 logln(" prev full moon: " + new Date(astro.getMoonTime(CalendarAstronomer.FULL_MOON, false)));
\r
175 logln(" next full moon: " + new Date(astro.getMoonTime(CalendarAstronomer.FULL_MOON, true)));
\r
180 static final long DAY_MS = 24*60*60*1000L;
\r
182 public void TestSunriseTimes() {
\r
184 // logln("Sunrise/Sunset times for San Jose, California, USA");
\r
185 // CalendarAstronomer astro = new CalendarAstronomer(-121.55, 37.20);
\r
186 // TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
\r
188 // We'll use a table generated by the UNSO website as our reference
\r
189 // From: http://aa.usno.navy.mil/
\r
190 //-Location: W079 25, N43 40
\r
191 //-Rise and Set for the Sun for 2001
\r
192 //-Zone: 4h West of Greenwich
\r
226 logln("Sunrise/Sunset times for Toronto, Canada");
\r
227 CalendarAstronomer astro = new CalendarAstronomer(-(79+25/60), 43+40/60);
\r
229 // As of ICU4J 2.8 the ICU4J time zones implement pass-through
\r
230 // to the underlying JDK. Because of variation in the
\r
231 // underlying JDKs, we have to use a fixed-offset
\r
232 // SimpleTimeZone to get consistent behavior between JDKs.
\r
233 // The offset we want is [-18000000, 3600000] (raw, dst).
\r
236 // TimeZone tz = TimeZone.getTimeZone("America/Montreal");
\r
237 TimeZone tz = new SimpleTimeZone(-18000000 + 3600000, "Montreal(FIXED)");
\r
239 GregorianCalendar cal = new GregorianCalendar(tz, Locale.US);
\r
240 GregorianCalendar cal2 = new GregorianCalendar(tz, Locale.US);
\r
242 cal.set(Calendar.YEAR, 2001);
\r
243 cal.set(Calendar.MONTH, Calendar.APRIL);
\r
244 cal.set(Calendar.DAY_OF_MONTH, 1);
\r
245 cal.set(Calendar.HOUR_OF_DAY, 12); // must be near local noon for getSunRiseSet to work
\r
247 DateFormat df = DateFormat.getTimeInstance(cal, DateFormat.MEDIUM, Locale.US);
\r
248 DateFormat df2 = DateFormat.getDateTimeInstance(cal, DateFormat.MEDIUM, DateFormat.MEDIUM, Locale.US);
\r
249 DateFormat day = DateFormat.getDateInstance(cal, DateFormat.MEDIUM, Locale.US);
\r
251 for (int i=0; i < 30; i++) {
\r
252 astro.setDate(cal.getTime());
\r
254 Date sunrise = new Date(astro.getSunRiseSet(true));
\r
255 Date sunset = new Date(astro.getSunRiseSet(false));
\r
257 cal2.setTime(cal.getTime());
\r
258 cal2.set(Calendar.SECOND, 0);
\r
259 cal2.set(Calendar.MILLISECOND, 0);
\r
261 cal2.set(Calendar.HOUR_OF_DAY, USNO[4*i+0]);
\r
262 cal2.set(Calendar.MINUTE, USNO[4*i+1]);
\r
263 Date exprise = cal2.getTime();
\r
264 cal2.set(Calendar.HOUR_OF_DAY, USNO[4*i+2]);
\r
265 cal2.set(Calendar.MINUTE, USNO[4*i+3]);
\r
266 Date expset = cal2.getTime();
\r
267 // Compute delta of what we got to the USNO data, in seconds
\r
268 int deltarise = Math.abs((int)(sunrise.getTime() - exprise.getTime()) / 1000);
\r
269 int deltaset = Math.abs((int)(sunset.getTime() - expset.getTime()) / 1000);
\r
271 // Allow a deviation of 0..MAX_DEV seconds
\r
272 // It would be nice to get down to 60 seconds, but at this
\r
273 // point that appears to be impossible without a redo of the
\r
274 // algorithm using something more advanced than Duffett-Smith.
\r
275 final int MAX_DEV = 180;
\r
276 if (deltarise > MAX_DEV || deltaset > MAX_DEV) {
\r
277 if (deltarise > MAX_DEV) {
\r
278 errln("FAIL: " + day.format(cal.getTime()) +
\r
279 ", Sunrise: " + df2.format(sunrise) +
\r
280 " (USNO " + df.format(exprise) +
\r
281 " d=" + deltarise + "s)");
\r
283 logln(day.format(cal.getTime()) +
\r
284 ", Sunrise: " + df.format(sunrise) +
\r
285 " (USNO " + df.format(exprise) + ")");
\r
287 if (deltaset > MAX_DEV) {
\r
288 errln("FAIL: " + day.format(cal.getTime()) +
\r
289 ", Sunset: " + df2.format(sunset) +
\r
290 " (USNO " + df.format(expset) +
\r
291 " d=" + deltaset + "s)");
\r
293 logln(day.format(cal.getTime()) +
\r
294 ", Sunset: " + df.format(sunset) +
\r
295 " (USNO " + df.format(expset) + ")");
\r
298 logln(day.format(cal.getTime()) +
\r
299 ", Sunrise: " + df.format(sunrise) +
\r
300 " (USNO " + df.format(exprise) + ")" +
\r
301 ", Sunset: " + df.format(sunset) +
\r
302 " (USNO " + df.format(expset) + ")");
\r
304 cal.add(Calendar.DATE, 1);
\r
307 // CalendarAstronomer a = new CalendarAstronomer(-(71+5/60), 42+37/60);
\r
309 // cal.set(cal.YEAR, 1986);
\r
310 // cal.set(cal.MONTH, cal.MARCH);
\r
311 // cal.set(cal.DATE, 10);
\r
312 // cal.set(cal.YEAR, 1988);
\r
313 // cal.set(cal.MONTH, cal.JULY);
\r
314 // cal.set(cal.DATE, 27);
\r
315 // a.setDate(cal.getTime());
\r
316 // long r = a.getSunRiseSet2(true);
\r
319 public void TestBasics() {
\r
320 // Check that our JD computation is the same as the book's (p. 88)
\r
321 CalendarAstronomer astro = new CalendarAstronomer();
\r
322 GregorianCalendar cal3 = new GregorianCalendar(TimeZone.getTimeZone("GMT"), Locale.US);
\r
323 DateFormat d3 = DateFormat.getDateTimeInstance(cal3, DateFormat.MEDIUM,DateFormat.MEDIUM,Locale.US);
\r
325 cal3.set(Calendar.YEAR, 1980);
\r
326 cal3.set(Calendar.MONTH, Calendar.JULY);
\r
327 cal3.set(Calendar.DATE, 27);
\r
328 astro.setDate(cal3.getTime());
\r
329 double jd = astro.getJulianDay() - 2447891.5;
\r
330 double exp = -3444;
\r
332 logln(d3.format(cal3.getTime()) + " => " + jd);
\r
334 errln("FAIL: " + d3.format(cal3.getTime()) + " => " + jd +
\r
335 ", expected " + exp);
\r
340 // cal3.set(cal3.YEAR, 1990);
\r
341 // cal3.set(cal3.MONTH, Calendar.JANUARY);
\r
342 // cal3.set(cal3.DATE, 1);
\r
343 // cal3.add(cal3.DATE, -1);
\r
344 // astro.setDate(cal3.getTime());
\r
348 public void TestMoonAge(){
\r
349 GregorianCalendar gc = new GregorianCalendar(new SimpleTimeZone(0,"GMT"));
\r
350 CalendarAstronomer calastro = new CalendarAstronomer();
\r
351 // more testcases are around the date 05/20/2012
\r
352 //ticket#3785 UDate ud0 = 1337557623000.0;
\r
353 double testcase[][] = {{2012, 5, 20 , 16 , 48, 59},
\r
354 {2012, 5, 20 , 16 , 47, 34},
\r
355 {2012, 5, 21, 00, 00, 00},
\r
356 {2012, 5, 20, 14, 55, 59},
\r
357 {2012, 5, 21, 7, 40, 40},
\r
358 {2023, 9, 25, 10,00, 00},
\r
359 {2008, 7, 7, 15, 00, 33},
\r
360 {1832, 9, 24, 2, 33, 41 },
\r
361 {2016, 1, 31, 23, 59, 59},
\r
362 {2099, 5, 20, 14, 55, 59}
\r
364 // Moon phase angle - Got from http://www.moonsystem.to/checkupe.htm
\r
365 double angle[] = {356.8493418421329, 356.8386760059673, 0.09625415252237701, 355.9986960782416, 3.5714026601303317, 124.26906744384183, 59.80247650195558, 357.54163205513123, 268.41779281511094, 4.82340276581624};
\r
366 double precision = PI/32;
\r
367 for(int i=0; i<testcase.length; i++){
\r
369 String testString = "CASE["+i+"]: Year "+(int)testcase[i][0]+" Month "+(int)testcase[i][1]+" Day "+
\r
370 (int)testcase[i][2]+" Hour "+(int)testcase[i][3]+" Minutes "+(int)testcase[i][4]+
\r
371 " Seconds "+(int)testcase[i][5];
\r
372 gc.set((int)testcase[i][0],(int)testcase[i][1]-1,(int)testcase[i][2],(int)testcase[i][3],(int)testcase[i][4], (int)testcase[i][5]);
\r
373 calastro.setDate(gc.getTime());
\r
374 double expectedAge = (angle[i]*PI)/180;
\r
375 double got = calastro.getMoonAge();
\r
377 if(!(got>expectedAge-precision && got<expectedAge+precision)){
\r
378 errln("FAIL: expected " + expectedAge +
\r
381 logln("PASS: expected " + expectedAge +
\r