Skip to content

Commit 0bd7893

Browse files
authored
Merge pull request #295 from dickermoshe/meeus-noaa-rise-set-fallback
NOAACalculator, MeeusCalculator: don't miss zmanim the sun only just reaches Thanks @dickermoshe
2 parents 745a337 + ac7b4fb commit 0bd7893

4 files changed

Lines changed: 71 additions & 0 deletions

File tree

‎src/main/java/com/kosherjava/zmanim/util/MeeusCalculator.java‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,18 @@ private double getSunRiseSetUTC(LocalDate localDate, double latitude, double lon
297297
double equationOfTime = noon.equationOfTime;
298298
double solarDeclination = noon.solarDeclination;
299299
double hourAngle = getSunHourAngle(latitude, solarDeclination, zenith, solarEvent);
300+
if (Double.isNaN(hourAngle)) {
301+
// Using the Sun's declination at noon, the Sun never reaches this zenith today. But the declination changes
302+
// during the day (by up to about 0.2° in 12 hours), so the Sun may still just reach it around midnight, when it
303+
// is at its lowest. Before reporting that there is no event, try again with the declination and equation of time
304+
// at that solar midnight: the one before sunrise, or the one after sunset.
305+
double noonmin = getSolarNoonMidnightUTC(julianDay, longitude, SolarEvent.NOON);
306+
double midnight = noonmin + (solarEvent == SolarEvent.SUNRISE ? -720 : 720);
307+
double tmidnight = getJulianCenturiesFromJulianDay(julianDay + midnight / 1440.0);
308+
equationOfTime = getEquationOfTime(tmidnight);
309+
solarDeclination = getSunDeclination(tmidnight);
310+
hourAngle = getSunHourAngle(latitude, solarDeclination, zenith, solarEvent);
311+
}
300312
double delta = longitude - Math.toDegrees(hourAngle);
301313
double timeUTC = 720 + (4 * delta) - equationOfTime;
302314

‎src/main/java/com/kosherjava/zmanim/util/NOAACalculator.java‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,17 @@ private static double getSunRiseSetUTC(LocalDate localDate, double latitude, dou
475475
double equationOfTime = getEquationOfTime(tnoon);
476476
double solarDeclination = getSunDeclination(tnoon);
477477
double hourAngle = getSunHourAngle(latitude, solarDeclination, zenith, solarEvent);
478+
if (Double.isNaN(hourAngle)) {
479+
// Using the Sun's declination at noon, the Sun never reaches this zenith today. But the declination changes
480+
// during the day (by up to about 0.2° in 12 hours), so the Sun may still just reach it around midnight, when it
481+
// is at its lowest. Before reporting that there is no event, try again with the declination and equation of time
482+
// at that solar midnight: the one before sunrise, or the one after sunset.
483+
double midnight = noonmin + (solarEvent == SolarEvent.SUNRISE ? -720 : 720);
484+
double tmidnight = getJulianCenturiesFromJulianDay(julianDay + midnight / 1440.0);
485+
equationOfTime = getEquationOfTime(tmidnight);
486+
solarDeclination = getSunDeclination(tmidnight);
487+
hourAngle = getSunHourAngle(latitude, solarDeclination, zenith, solarEvent);
488+
}
478489
double delta = longitude - Math.toDegrees(hourAngle);
479490
double timeDiff = 4 * delta;
480491
double timeUTC = 720 + timeDiff - equationOfTime;

‎src/test/java/com/kosherjava/zmanim/util/MeeusCalculatorTest.java‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,30 @@ public void getUTCSunriseWithDeltaTDisabled() {
244244
}
245245
}
246246

247+
/**
248+
* Days when the Sun only just reaches the zenith, around midnight. Using the Sun's declination at noon the zenith looks
249+
* out of reach, but using the declination at solar midnight it is reached, so these return a time rather than NaN.
250+
*/
251+
@Test
252+
public void getUTCSunRiseSetWhenOnlyJustReached() {
253+
GeoLocation london = new GeoLocation("London", 51.5074, -0.1278, 0, TestLocations.UTC);
254+
GeoLocation arctic = new GeoLocation("Arctic", 75.51550698948259, -0.9961193842273985, 1516.0617032522935,
255+
TestLocations.UTC);
256+
Object[][] cases = {
257+
{"London 16.1\u00b0 alos, Sun just reaches it", london, "2024-06-03", 106.1, true, 0.17268715},
258+
{"London 18\u00b0 tzais, Sun just reaches it", london, "2024-07-20", 108.0, false, 23.85897993},
259+
{"75.5\u00b0N sunrise just after midnight", arctic, "2093-04-22", ZENITH, true, 0.22098753},
260+
};
261+
for (Object[] c : cases) {
262+
GeoLocation location = (GeoLocation) c[1];
263+
double zenith = (double) c[3];
264+
double actual = (boolean) c[4]
265+
? calculator().getUTCSunrise(date((String) c[2]), location, zenith, zenith == ZENITH)
266+
: calculator().getUTCSunset(date((String) c[2]), location, zenith, zenith == ZENITH);
267+
assertUtcHour((String) c[0], (double) c[5], actual);
268+
}
269+
}
270+
247271
@Test(expected = IllegalArgumentException.class)
248272
public void getTimeAtAzimuthRejectsUnsupportedAzimuth() {
249273
calculator().getTimeAtAzimuth(date("2017-10-17"), geo("NJ"), 123.0);

‎src/test/java/com/kosherjava/zmanim/util/NOAACalculatorTest.java‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,30 @@ public void getUTCSunriseWithoutElevationAdjustment() {
230230
}
231231
}
232232

233+
/**
234+
* Days when the Sun only just reaches the zenith, around midnight. Using the Sun's declination at noon the zenith looks
235+
* out of reach, but using the declination at solar midnight it is reached, so these return a time rather than NaN.
236+
*/
237+
@Test
238+
public void getUTCSunRiseSetWhenOnlyJustReached() {
239+
GeoLocation london = new GeoLocation("London", 51.5074, -0.1278, 0, TestLocations.UTC);
240+
GeoLocation arctic = new GeoLocation("Arctic", 75.51550698948259, -0.9961193842273985, 1516.0617032522935,
241+
TestLocations.UTC);
242+
Object[][] cases = {
243+
{"London 16.1\u00b0 alos, Sun just reaches it", london, "2024-06-03", 106.1, true, 0.17183556},
244+
{"London 18\u00b0 tzais, Sun just reaches it", london, "2024-07-20", 108.0, false, 23.85934340},
245+
{"75.5\u00b0N sunrise just after midnight", arctic, "2093-04-22", ZENITH, true, 0.21591651},
246+
};
247+
for (Object[] c : cases) {
248+
GeoLocation location = (GeoLocation) c[1];
249+
double zenith = (double) c[3];
250+
double actual = (boolean) c[4]
251+
? calculator().getUTCSunrise(date((String) c[2]), location, zenith, zenith == ZENITH)
252+
: calculator().getUTCSunset(date((String) c[2]), location, zenith, zenith == ZENITH);
253+
assertUtcHour((String) c[0], (double) c[5], actual);
254+
}
255+
}
256+
233257
@Test(expected = IllegalArgumentException.class)
234258
public void getTimeAtAzimuthRejectsUnsupportedAzimuth() {
235259
calculator().getTimeAtAzimuth(date("2017-10-17"), geo("NJ"), 123.0);

0 commit comments

Comments
 (0)