1/* 2 ******************************************************************************* 3 * Copyright (C) 1996-2010, International Business Machines Corporation and * 4 * others. All Rights Reserved. * 5 ******************************************************************************* 6 */ 7package com.ibm.icu.dev.test.calendar; 8 9// AstroTest 10 11import java.util.Date; 12import java.util.Locale; 13 14import com.ibm.icu.dev.test.TestFmwk; 15import com.ibm.icu.impl.CalendarAstronomer; 16import com.ibm.icu.impl.CalendarAstronomer.Ecliptic; 17import com.ibm.icu.impl.CalendarAstronomer.Equatorial; 18import com.ibm.icu.text.DateFormat; 19import com.ibm.icu.util.Calendar; 20import com.ibm.icu.util.GregorianCalendar; 21import com.ibm.icu.util.SimpleTimeZone; 22import com.ibm.icu.util.TimeZone; 23 24// TODO: try finding next new moon after 07/28/1984 16:00 GMT 25 26public class AstroTest extends TestFmwk { 27 public static void main(String[] args) throws Exception { 28 new AstroTest().run(args); 29 } 30 31 static final double PI = Math.PI; 32 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 }, 40 }; 41 logln(""); 42 for (int i = 0; i < tests.length; i++) { 43 gc.clear(); 44 gc.set((int)tests[i][0], (int)tests[i][1]-1, (int)tests[i][2], (int)tests[i][3], (int) tests[i][4]); 45 46 astro.setDate(gc.getTime()); 47 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); 54 } else { 55 errln("FAIL: longitude(" + longitude + 56 ") != tests[i][5](" + tests[i][5] + 57 ") for test " + i); 58 } 59 } 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); 66 } else { 67 errln("FAIL: result.ascension(" + result.ascension + 68 ") != tests[i][6](" + tests[i][6] + 69 ") for test " + i); 70 } 71 } 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); 77 } else { 78 errln("FAIL: result.declination(" + result.declination + 79 ") != tests[i][7](" + tests[i][7] + 80 ") for test " + i); 81 } 82 } 83 } 84 } 85 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 }, 92 }; 93 logln(""); 94 95 for (int i = 0; i < tests.length; i++) { 96 gc.clear(); 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()); 99 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); 106 } else { 107 errln("FAIL: result.ascension(" + result.ascension + 108 ") != tests[i][5](" + tests[i][5] + 109 ") for test " + i); 110 } 111 } 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); 117 } else { 118 errln("FAIL: result.declination(" + result.declination + 119 ") != tests[i][6](" + tests[i][6] + 120 ") for test " + i); 121 } 122 } 123 } 124 } 125 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()); 130 } 131 132 public void TestCoverage() { 133 GregorianCalendar cal = new GregorianCalendar(1958, Calendar.AUGUST, 15); 134 Date then = cal.getTime(); 135 CalendarAstronomer myastro = new CalendarAstronomer(then); 136 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); 141 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); 146 147 CalendarAstronomer myastro3 = new CalendarAstronomer(); 148 myastro3.setJulianDay((4713 + 2000) * 365.25); 149 150 CalendarAstronomer[] astronomers = { 151 myastro, myastro2, myastro3, myastro2 // check cache 152 153 }; 154 155 for (int i = 0; i < astronomers.length; ++i) { 156 CalendarAstronomer astro = astronomers[i]; 157 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))); 176 } 177 178 } 179 180 static final long DAY_MS = 24*60*60*1000L; 181 182 public void TestSunriseTimes() { 183 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"); 187 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 193 int[] USNO = { 194 6,59, 19,45, 195 6,57, 19,46, 196 6,56, 19,47, 197 6,54, 19,48, 198 6,52, 19,49, 199 6,50, 19,51, 200 6,48, 19,52, 201 6,47, 19,53, 202 6,45, 19,54, 203 6,43, 19,55, 204 6,42, 19,57, 205 6,40, 19,58, 206 6,38, 19,59, 207 6,36, 20, 0, 208 6,35, 20, 1, 209 6,33, 20, 3, 210 6,31, 20, 4, 211 6,30, 20, 5, 212 6,28, 20, 6, 213 6,27, 20, 7, 214 6,25, 20, 8, 215 6,23, 20,10, 216 6,22, 20,11, 217 6,20, 20,12, 218 6,19, 20,13, 219 6,17, 20,14, 220 6,16, 20,16, 221 6,14, 20,17, 222 6,13, 20,18, 223 6,11, 20,19, 224 }; 225 226 logln("Sunrise/Sunset times for Toronto, Canada"); 227 CalendarAstronomer astro = new CalendarAstronomer(-(79+25/60), 43+40/60); 228 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). 234 // [aliu 10/15/03] 235 236 // TimeZone tz = TimeZone.getTimeZone("America/Montreal"); 237 TimeZone tz = new SimpleTimeZone(-18000000 + 3600000, "Montreal(FIXED)"); 238 239 GregorianCalendar cal = new GregorianCalendar(tz, Locale.US); 240 GregorianCalendar cal2 = new GregorianCalendar(tz, Locale.US); 241 cal.clear(); 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 246 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); 250 251 for (int i=0; i < 30; i++) { 252 astro.setDate(cal.getTime()); 253 254 Date sunrise = new Date(astro.getSunRiseSet(true)); 255 Date sunset = new Date(astro.getSunRiseSet(false)); 256 257 cal2.setTime(cal.getTime()); 258 cal2.set(Calendar.SECOND, 0); 259 cal2.set(Calendar.MILLISECOND, 0); 260 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); 270 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)"); 282 } else { 283 logln(day.format(cal.getTime()) + 284 ", Sunrise: " + df.format(sunrise) + 285 " (USNO " + df.format(exprise) + ")"); 286 } 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)"); 292 } else { 293 logln(day.format(cal.getTime()) + 294 ", Sunset: " + df.format(sunset) + 295 " (USNO " + df.format(expset) + ")"); 296 } 297 } else { 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) + ")"); 303 } 304 cal.add(Calendar.DATE, 1); 305 } 306 307// CalendarAstronomer a = new CalendarAstronomer(-(71+5/60), 42+37/60); 308// cal.clear(); 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); 317 } 318 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); 324 cal3.clear(); 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; 330 double exp = -3444; 331 if (jd == exp) { 332 logln(d3.format(cal3.getTime()) + " => " + jd); 333 } else { 334 errln("FAIL: " + d3.format(cal3.getTime()) + " => " + jd + 335 ", expected " + exp); 336 } 337 338 339// cal3.clear(); 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()); 345// astro.foo(); 346 } 347 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} 363 }; 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++){ 368 gc.clear(); 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(); 376 logln(testString); 377 if(!(got>expectedAge-precision && got<expectedAge+precision)){ 378 errln("FAIL: expected " + expectedAge + 379 " got " + got); 380 }else{ 381 logln("PASS: expected " + expectedAge + 382 " got " + got); 383 } 384 } 385 } 386} 387