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