diff --git a/src/main/java/org/shredzone/commons/suncalc/MoonTimes.java b/src/main/java/org/shredzone/commons/suncalc/MoonTimes.java index e7a21f9..7f27cbf 100644 --- a/src/main/java/org/shredzone/commons/suncalc/MoonTimes.java +++ b/src/main/java/org/shredzone/commons/suncalc/MoonTimes.java @@ -108,7 +108,7 @@ public MoonTimes execute() { double y_minus = correctedMoonHeight(jd); int maxHours = fullCycle ? 365 * 24 : 24; - for (int hour = 1; hour <= maxHours; hour += 2) { + for (int hour = 1; hour < maxHours; hour += 2) { double y_0 = correctedMoonHeight(jd.atHour(hour)); double y_plus = correctedMoonHeight(jd.atHour(hour + 1.0)); @@ -117,13 +117,21 @@ public MoonTimes execute() { if (qi.getNumberOfRoots() == 1) { if (y_minus < 0.0) { - rise = qi.getRoot1() + hour; + if (rise == null) { + rise = qi.getRoot1() + hour; + } } else { - set = qi.getRoot1() + hour; + if (set == null) { + set = qi.getRoot1() + hour; + } } } else if (qi.getNumberOfRoots() == 2) { - rise = hour + (ye < 0.0 ? qi.getRoot2() : qi.getRoot1()); - set = hour + (ye < 0.0 ? qi.getRoot1() : qi.getRoot2()); + if (rise == null) { + rise = hour + (ye < 0.0 ? qi.getRoot2() : qi.getRoot1()); + } + if (set == null) { + set = hour + (ye < 0.0 ? qi.getRoot1() : qi.getRoot2()); + } } if (rise != null && set != null) { diff --git a/src/main/java/org/shredzone/commons/suncalc/SunTimes.java b/src/main/java/org/shredzone/commons/suncalc/SunTimes.java index e10d46c..5cba533 100644 --- a/src/main/java/org/shredzone/commons/suncalc/SunTimes.java +++ b/src/main/java/org/shredzone/commons/suncalc/SunTimes.java @@ -263,7 +263,7 @@ public SunTimes execute() { double y_minus = correctedSunHeight(jd); int maxHours = fullCycle ? 365 * 24 : 24; - for (int hour = 1; hour <= maxHours; hour += 2) { + for (int hour = 1; hour < maxHours; hour += 2) { double y_0 = correctedSunHeight(jd.atHour(hour)); double y_plus = correctedSunHeight(jd.atHour(hour + 1.0)); @@ -272,13 +272,21 @@ public SunTimes execute() { if (qi.getNumberOfRoots() == 1) { if (y_minus < 0.0) { - rise = qi.getRoot1() + hour; + if (rise == null) { + rise = qi.getRoot1() + hour; + } } else { - set = qi.getRoot1() + hour; + if (set == null) { + set = qi.getRoot1() + hour; + } } } else if (qi.getNumberOfRoots() == 2) { - rise = hour + (ye < 0.0 ? qi.getRoot2() : qi.getRoot1()); - set = hour + (ye < 0.0 ? qi.getRoot1() : qi.getRoot2()); + if (rise == null) { + rise = hour + (ye < 0.0 ? qi.getRoot2() : qi.getRoot1()); + } + if (set == null) { + set = hour + (ye < 0.0 ? qi.getRoot1() : qi.getRoot2()); + } } double xe = qi.getXe(); @@ -290,7 +298,7 @@ public SunTimes execute() { } } - if (rise != null && set != null && nadir != null && noon != null) { + if (rise != null && set != null && noon != null && nadir != null) { break; } diff --git a/src/test/java/org/shredzone/commons/suncalc/MoonTimesTest.java b/src/test/java/org/shredzone/commons/suncalc/MoonTimesTest.java index c4eabb1..bc6c15f 100644 --- a/src/test/java/org/shredzone/commons/suncalc/MoonTimesTest.java +++ b/src/test/java/org/shredzone/commons/suncalc/MoonTimesTest.java @@ -13,10 +13,14 @@ */ package org.shredzone.commons.suncalc; -import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.assertThat; import static org.shredzone.commons.suncalc.Locations.*; +import java.util.Calendar; +import java.util.Date; +import java.util.TimeZone; + import org.junit.Test; /** @@ -87,4 +91,47 @@ public void testSingapore() { assertThat("set", mt.getSet(), DateMatcher.is("2017-07-13T02:08:54Z")); } + @Test + public void testSequence() { + long acceptableError = 60 * 1000L; + + Date riseBefore = createDate(2017, 11, 25, 12, 0); + Date riseAfter = createDate(2017, 11, 26, 12, 29); + Date setBefore = createDate(2017, 11, 25, 21, 49); + Date setAfter = createDate(2017, 11, 26, 22, 55); + + for (int hour = 0; hour < 24; hour++) { + for (int minute = 0; minute < 60; minute++) { + MoonTimes times = MoonTimes.compute() + .at(COLOGNE) + .on(2017, 11, 25, hour, minute, 0).utc() + .fullCycle() + .execute(); + + if (hour < 12 || (hour == 12 && minute == 0)) { + long diff = Math.abs(times.getRise().getTime() - riseBefore.getTime()); + assertThat("rise @" + hour + ":" + minute, diff, is(lessThan(acceptableError))); + } else { + long diff = Math.abs(times.getRise().getTime() - riseAfter.getTime()); + assertThat("rise @" + hour + ":" + minute, diff, is(lessThan(acceptableError))); + } + + if (hour < 21 || (hour == 21 && minute <= 49)) { + long diff = Math.abs(times.getSet().getTime() - setBefore.getTime()); + assertThat("set @" + hour + ":" + minute, diff, is(lessThan(acceptableError))); + } else { + long diff = Math.abs(times.getSet().getTime() - setAfter.getTime()); + assertThat("set @" + hour + ":" + minute, diff, is(lessThan(acceptableError))); + } + } + } + } + + private Date createDate(int year, int month, int day, int hour, int minute) { + Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC")); + cal.clear(); + cal.set(year, month - 1, day, hour, minute, 0); + return cal.getTime(); + } + } diff --git a/src/test/java/org/shredzone/commons/suncalc/SunTimesTest.java b/src/test/java/org/shredzone/commons/suncalc/SunTimesTest.java index c6010f7..54ff720 100644 --- a/src/test/java/org/shredzone/commons/suncalc/SunTimesTest.java +++ b/src/test/java/org/shredzone/commons/suncalc/SunTimesTest.java @@ -17,9 +17,11 @@ import static org.junit.Assert.assertThat; import static org.shredzone.commons.suncalc.Locations.*; +import java.util.Calendar; import java.util.Date; import java.util.EnumMap; import java.util.Map; +import java.util.TimeZone; import org.hamcrest.Matcher; import org.junit.Test; @@ -112,6 +114,49 @@ public void testSingapore() { assertTimes(t1, "2017-08-10T23:05:06Z", "2017-08-10T11:14:56Z", "2017-08-10T05:08:44Z"); } + @Test + public void testSequence() { + long acceptableError = 62 * 1000L; + + Date riseBefore = createDate(2017, 11, 25, 7, 4); + Date riseAfter = createDate(2017, 11, 26, 7, 6); + Date setBefore = createDate(2017, 11, 25, 15, 33); + Date setAfter = createDate(2017, 11, 26, 15, 32); + + for (int hour = 0; hour < 24; hour++) { + for (int minute = 0; minute < 60; minute++) { + SunTimes times = SunTimes.compute() + .at(COLOGNE) + .on(2017, 11, 25, hour, minute, 0).utc() + .fullCycle() + .execute(); + + if (hour < 7 || (hour == 7 && minute <= 4)) { + long diff = Math.abs(times.getRise().getTime() - riseBefore.getTime()); + assertThat("rise @" + hour + ":" + minute, diff, is(lessThan(acceptableError))); + } else { + long diff = Math.abs(times.getRise().getTime() - riseAfter.getTime()); + assertThat("rise @" + hour + ":" + minute, diff, is(lessThan(acceptableError))); + } + + if (hour < 15 || (hour == 15 && minute <= 33)) { + long diff = Math.abs(times.getSet().getTime() - setBefore.getTime()); + assertThat("set @" + hour + ":" + minute, diff, is(lessThan(acceptableError))); + } else { + long diff = Math.abs(times.getSet().getTime() - setAfter.getTime()); + assertThat("set @" + hour + ":" + minute, diff, is(lessThan(acceptableError))); + } + } + } + } + + private Date createDate(int year, int month, int day, int hour, int minute) { + Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC")); + cal.clear(); + cal.set(year, month - 1, day, hour, minute, 0); + return cal.getTime(); + } + private void assertTimes(SunTimes t, String rise, String set, String noon) { if (rise != null) { assertThat("sunrise", t.getRise(), DateMatcher.is(rise));