[astro] Refactor Moon Distance (#19974)

* Review Moon Distance and factorization of MoonCalc

Signed-off-by: gael@lhopital.org <gael@lhopital.org>
This commit is contained in:
Gaël L'hopital
2026-01-09 09:27:09 +01:00
committed by GitHub
parent 77737c8066
commit dfa2adf2c1
15 changed files with 463 additions and 235 deletions
@@ -49,14 +49,9 @@ public final class AstroBindingConstants {
public static final String EVENT_PHASE_FULL = "FULL";
public static final String EVENT_PHASE_NEW = "NEW";
public static final String EVENT_PERIGEE = "PERIGEE";
public static final String EVENT_APOGEE = "APOGEE";
// event channelIds
public static final String EVENT_CHANNEL_ID_MOON_PHASE = "phase#event";
public static final String EVENT_CHANNEL_ID_ECLIPSE = "eclipse#event";
public static final String EVENT_CHANNEL_ID_PERIGEE = "perigee#event";
public static final String EVENT_CHANNEL_ID_APOGEE = "apogee#event";
public static final String EVENT_CHANNEL_ID_RISE = "rise#event";
public static final String EVENT_CHANNEL_ID_SET = "set#event";
@@ -18,14 +18,15 @@ import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Calendar;
import java.util.Locale;
import java.util.Set;
import java.util.TimeZone;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.astro.internal.model.DistanceType;
import org.openhab.binding.astro.internal.model.Eclipse;
import org.openhab.binding.astro.internal.model.EclipseKind;
import org.openhab.binding.astro.internal.model.EclipseType;
import org.openhab.binding.astro.internal.model.Moon;
import org.openhab.binding.astro.internal.model.MoonDistance;
import org.openhab.binding.astro.internal.model.MoonPhase;
import org.openhab.binding.astro.internal.model.MoonPhaseName;
import org.openhab.binding.astro.internal.model.Position;
@@ -95,16 +96,8 @@ public class MoonCalc {
}
});
double decimalYear = DateTimeUtils.getDecimalYear(calendar);
MoonDistance apogee = moon.getApogee();
double apogeeJd = getApogee(julianDate, decimalYear);
apogee.setDate(DateTimeUtils.toCalendar(apogeeJd, zone, locale));
apogee.setDistance(getDistance(apogeeJd));
MoonDistance perigee = moon.getPerigee();
double perigeeJd = getPerigee(julianDate, decimalYear);
perigee.setDate(DateTimeUtils.toCalendar(perigeeJd, zone, locale));
perigee.setDistance(getDistance(perigeeJd));
Set.of(DistanceType.APOGEE, DistanceType.PERIGEE)
.forEach(type -> moon.setDistance(type, MoonDistanceCalc.get(type, julianDate)));
return moon;
}
@@ -118,9 +111,7 @@ public class MoonCalc {
setMoonPhase(calendar, moon, zone, locale);
setAzimuthElevationZodiac(julianDate, latitude, longitude, moon);
MoonDistance distance = moon.getDistance();
distance.setDate(calendar);
distance.setDistance(getDistance(julianDate));
moon.setDistance(DistanceType.CURRENT, MoonDistanceCalc.calculate(julianDate));
}
/**
@@ -437,88 +428,6 @@ public class MoonCalc {
return eclipseJd;
}
/**
* Calculates the date, where the moon is furthest away from the earth.
*/
private double getApogee(double julianDate, double decimalYear) {
double k = Math.floor((decimalYear - 1999.97) * 13.2555) + .5;
double jd = 0;
do {
double t = k / 1325.55;
double d = 171.9179 + 335.9106046 * k - .010025 * t * t - .00001156 * t * t * t
+ .000000055 * t * t * t * t;
double m = 347.3477 + 27.1577721 * k - .0008323 * t * t - .000001 * t * t * t;
double f = 316.6109 + 364.5287911 * k - .0125131 * t * t - .0000148 * t * t * t;
jd = 2451534.6698 + 27.55454988 * k - .0006886 * t * t - .000001098 * t * t * t + .0000000052 * t * t
+ .4392 * sinDeg(2 * d) + .0684 * sinDeg(4 * d) + (.0456 - .00011 * t) * sinDeg(m)
+ (.0426 - .00011 * t) * sinDeg(2 * d - m) + .0212 * sinDeg(2 * f);
jd += -.0189 * sinDeg(d) + .0144 * sinDeg(6 * d) + .0113 * sinDeg(4 * d - m) + .0047 * sinDeg(2 * d + 2 * f)
+ .0036 * sinDeg(d + m) + .0035 * sinDeg(8 * d) + .0034 * sinDeg(6 * d - m)
- .0034 * sinDeg(2 * d - 2 * f) + .0022 * sinDeg(2 * d - 2 * m) - .0017 * sinDeg(3 * d);
jd += .0013 * sinDeg(4 * d + 2 * f) + .0011 * sinDeg(8 * d - m) + .001 * sinDeg(4 * d - 2 * m)
+ .0009 * sinDeg(10 * d) + .0007 * sinDeg(3 * d + m) + .0006 * sinDeg(2 * m)
+ .0005 * sinDeg(2 * d + m) + .0005 * sinDeg(2 * d + 2 * m) + .0004 * sinDeg(6 * d + 2 * f);
jd += .0004 * sinDeg(6 * d - 2 * m) + .0004 * sinDeg(10 * d - m) - .0004 * sinDeg(5 * d)
- .0004 * sinDeg(4 * d - 2 * f) + .0003 * sinDeg(2 * f + m) + .0003 * sinDeg(12 * d)
+ .0003 * sinDeg(2 * d + 2 * f - m) - .0003 * sinDeg(d - m);
k += 1;
} while (jd < julianDate);
return jd;
}
/**
* Calculates the date, where the moon is closest to the earth.
*/
private double getPerigee(double julianDate, double decimalYear) {
double k = Math.floor((decimalYear - 1999.97) * 13.2555);
double jd = 0;
do {
double t = k / 1325.55;
double d = 171.9179 + 335.9106046 * k - .010025 * t * t - .00001156 * t * t * t
+ .000000055 * t * t * t * t;
double m = 347.3477 + 27.1577721 * k - .0008323 * t * t - .000001 * t * t * t;
double f = 316.6109 + 364.5287911 * k - .0125131 * t * t - .0000148 * t * t * t;
jd = 2451534.6698 + 27.55454988 * k - .0006886 * t * t - .000001098 * t * t * t + .0000000052 * t * t
- 1.6769 * sinDeg(2 * d) + .4589 * sinDeg(4 * d) - .1856 * sinDeg(6 * d) + .0883 * sinDeg(8 * d);
jd += -(.0773 + .00019 * t) * sinDeg(2 * d - m) + (.0502 - .00013 * t) * sinDeg(m) - .046 * sinDeg(10 * d)
+ (.0422 - .00011 * t) * sinDeg(4 * d - m) - .0256 * sinDeg(6 * d - m) + .0253 * sinDeg(12 * d)
+ .0237 * sinDeg(d);
jd += .0162 * sinDeg(8 * d - m) - .0145 * sinDeg(14 * d) + .0129 * sinDeg(2 * f) - .0112 * sinDeg(3 * d)
- .0104 * sinDeg(10 * d - m) + .0086 * sinDeg(16 * d) + .0069 * sinDeg(12 * d - m)
+ .0066 * sinDeg(5 * d) - .0053 * sinDeg(2 * d + 2 * f);
jd += -.0052 * sinDeg(18 * d) - .0046 * sinDeg(14 * d - m) - .0041 * sinDeg(7 * d)
+ .004 * sinDeg(2 * d + m) + .0032 * sinDeg(20 * d) - .0032 * sinDeg(d + m)
+ .0031 * sinDeg(16 * d - m);
jd += -.0029 * sinDeg(4 * d + m) - .0027 * sinDeg(2 * d - 2 * m) + .0024 * sinDeg(4 * d - 2 * m)
- .0021 * sinDeg(6 * d - 2 * m) - .0021 * sinDeg(22 * d) - .0021 * sinDeg(18 * d - m);
jd += .0019 * sinDeg(6 * d + m) - .0018 * sinDeg(11 * d) - .0014 * sinDeg(8 * d + m)
- .0014 * sinDeg(4 * d - 2 * f) - .0014 * sinDeg(6 * d - 2 * f) + .0014 * sinDeg(3 * d + m)
- .0014 * sinDeg(5 * d + m) + .0013 * sinDeg(13 * d);
jd += .0013 * sinDeg(20 * d - m) + .0011 * sinDeg(3 * d + 2 * m) - .0011 * sinDeg(4 * d + 2 * f - 2 * m)
- .001 * sinDeg(d + 2 * m) - .0009 * sinDeg(22 * d - m) - .0008 * sinDeg(4 * f)
+ .0008 * sinDeg(6 * d - 2 * f) + .0008 * sinDeg(2 * d - 2 * f + m);
jd += .0007 * sinDeg(2 * m) + .0007 * sinDeg(2 * f - m) + .0007 * sinDeg(2 * d + 4 * f)
- .0006 * sinDeg(2 * f - 2 * m) - .0006 * sinDeg(2 * d - 2 * f + 2 * m) + .0006 * sinDeg(24 * d)
+ .0005 * sinDeg(4 * d - 4 * f) + .0005 * sinDeg(2 * d + 2 * m) - .0004 * sinDeg(d - m)
+ .0027 * sinDeg(9 * d) + .0027 * sinDeg(4 * d + 2 * f);
k += 1;
} while (jd < julianDate);
return jd;
}
/**
* Calculates the distance from the moon to earth.
*/
private double getDistance(double jd) {
double t = (jd - 2451545) / 36525;
double d = 297.8502042 + 445267.11151686 * t - .00163 * t * t + t * t * t / 545868 - t * t * t * t / 113065000;
double m = 357.5291092 + 35999.0502909 * t - .0001536 * t * t + t * t * t / 24490000;
double m1 = 134.9634114 + 477198.8676313 * t + .008997 * t * t + t * t * t / 69699 - t * t * t * t / 14712000;
double f = 93.27209929999999 + 483202.0175273 * t - .0034029 * t * t - t * t * t / 3526000
+ t * t * t * t / 863310000;
return 385000.56 + getCoefficient(d, m, m1, f) / 1000;
}
private double[] calcMoon(double t) {
double p2 = 6.283185307;
double arc = 206264.8062;
@@ -647,27 +556,6 @@ public class MoonCalc {
return ret;
}
private double getCoefficient(double d, double m, double m1, double f) {
int[] kd = new int[] { 0, 2, 2, 0, 0, 0, 2, 2, 2, 2, 0, 1, 0, 2, 0, 0, 4, 0, 4, 2, 2, 1, 1, 2, 2, 4, 2, 0, 2, 2,
1, 2, 0, 0, 2, 2, 2, 4, 0, 3, 2, 4, 0, 2, 2, 2, 4, 0, 4, 1, 2, 0, 1, 3, 4, 2, 0, 1, 2, 2 };
int[] km = new int[] { 0, 0, 0, 0, 1, 0, 0, -1, 0, -1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, -1, 0, 0, 0, 1, 0,
-1, 0, -2, 1, 2, -2, 0, 0, -1, 0, 0, 1, -1, 2, 2, 1, -1, 0, 0, -1, 0, 1, 0, 1, 0, 0, -1, 2, 1, 0, 0 };
int[] km1 = new int[] { 1, -1, 0, 2, 0, 0, -2, -1, 1, 0, -1, 0, 1, 0, 1, 1, -1, 3, -2, -1, 0, -1, 0, 1, 2, 0,
-3, -2, -1, -2, 1, 0, 2, 0, -1, 1, 0, -1, 2, -1, 1, -2, -1, -1, -2, 0, 1, 4, 0, -2, 0, 2, 1, -2, -3, 2,
1, -1, 3, -1 };
int[] kf = new int[] { 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, -2, 2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
0, 0, 0, 0, 0, 0, -2, 2, 0, 2, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, -2, -2, 0, 0, 0, 0, 0, 0, 0, -2 };
int[] kr = new int[] { -20905355, -3699111, -2955968, -569925, 48888, -3149, 246158, -152138, -170733, -204586,
-129620, 108743, 104755, 10321, 0, 79661, -34782, -23210, -21636, 24208, 30824, -8379, -16675, -12831,
-10445, -11650, 14403, -7003, 0, 10056, 6322, -9884, 5751, 0, -4950, 4130, 0, -3958, 0, 3258, 2616,
-1897, -2117, 2354, 0, 0, -1423, -1117, -1571, -1739, 0, -4421, 0, 0, 0, 0, 1165, 0, 0, 8752 };
double sr = 0;
for (int t = 0; t < 60; t++) {
sr += kr[t] * cosDeg(kd[t] * d + km[t] * m + km1[t] * m1 + kf[t] * f);
}
return sr;
}
/**
* Sets the azimuth, elevation and zodiac in the moon object.
*/
@@ -0,0 +1,141 @@
/*
* Copyright (c) 2010-2026 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.astro.internal.calc;
import static java.lang.Math.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.astro.internal.model.DistanceType;
import org.openhab.binding.astro.internal.model.MoonDistance;
import org.openhab.binding.astro.internal.util.AstroConstants;
import org.openhab.binding.astro.internal.util.DateTimeUtils;
/**
* Moon Distance Calculator
*
* @author Gaël L'hopital - Initial contribution
*/
@NonNullByDefault
public class MoonDistanceCalc {
private static final double ANOMALISTIC_MONTH = 27.55454988;
private static final double JDE_0 = 2451534.6698;
private static final int[] KD = new int[] { 0, 2, 2, 0, 0, 0, 2, 2, 2, 2, 0, 1, 0, 2, 0, 0, 4, 0, 4, 2, 2, 1, 1, 2,
2, 4, 2, 0, 2, 2, 1, 2, 0, 0, 2, 2, 2, 4, 0, 3, 2, 4, 0, 2, 2, 2, 4, 0, 4, 1, 2, 0, 1, 3, 4, 2, 0, 1, 2,
2 };
private static final int[] KM = new int[] { 0, 0, 0, 0, 1, 0, 0, -1, 0, -1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1,
-1, 0, 0, 0, 1, 0, -1, 0, -2, 1, 2, -2, 0, 0, -1, 0, 0, 1, -1, 2, 2, 1, -1, 0, 0, -1, 0, 1, 0, 1, 0, 0, -1,
2, 1, 0, 0 };
private static final int[] KM1 = new int[] { 1, -1, 0, 2, 0, 0, -2, -1, 1, 0, -1, 0, 1, 0, 1, 1, -1, 3, -2, -1, 0,
-1, 0, 1, 2, 0, -3, -2, -1, -2, 1, 0, 2, 0, -1, 1, 0, -1, 2, -1, 1, -2, -1, -1, -2, 0, 1, 4, 0, -2, 0, 2, 1,
-2, -3, 2, 1, -1, 3, -1 };
private static final int[] KF = new int[] { 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, -2, 2, -2, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, -2, 2, 0, 2, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, -2, -2, 0, 0, 0, 0, 0, 0,
0, -2 };
private static final int[] KR = new int[] { -20905355, -3699111, -2955968, -569925, 48888, -3149, 246158, -152138,
-170733, -204586, -129620, 108743, 104755, 10321, 0, 79661, -34782, -23210, -21636, 24208, 30824, -8379,
-16675, -12831, -10445, -11650, 14403, -7003, 0, 10056, 6322, -9884, 5751, 0, -4950, 4130, 0, -3958, 0,
3258, 2616, -1897, -2117, 2354, 0, 0, -1423, -1117, -1571, -1739, 0, -4421, 0, 0, 0, 0, 1165, 0, 0, 8752 };
/**
* Calculates the distance from the moon to earth in metres
*/
public static MoonDistance calculate(double jd) {
double t = DateTimeUtils.toJulianCenturies(jd);
double t2 = t * t;
double t3 = t2 * t;
double t4 = t3 * t;
double d = toRadians(297.8502042 + 445267.11151686 * t - .00163 * t2 + t3 / 545868 - t4 / 113065000);
double m = toRadians(AstroConstants.E05_0 + 35999.0502909 * t - .0001536 * t2 + t3 / 24490000);
double m1 = toRadians(134.9634114 + 477198.8676313 * t + .008997 * t2 + t3 / 69699 - t4 / 14712000);
double f = toRadians(93.2720993 + 483202.0175273 * t - .0034029 * t2 - t3 / 3526000 + t4 / 863310000);
return new MoonDistance(jd, 385000560 + getCoefficient(d, m, m1, f));
}
public static MoonDistance get(DistanceType type, double julianDate) {
if (DistanceType.CURRENT.equals(type)) {
throw new IllegalArgumentException("MoonDistanceCalc.get only supports APOGEE and PERIGEE");
}
double moment = getApogeePerigee(type, julianDate);
return calculate(moment);
}
private static double getCoefficient(double d, double m, double m1, double f) {
double sr = 0;
for (int t = 0; t < 60; t++) {
sr += KR[t] * cos(KD[t] * d + KM[t] * m + KM1[t] * m1 + KF[t] * f);
}
return sr;
}
/**
* Calculates the Julian date of the specified lunar distance extreme relative to the earth.
* Depending on the given {@link DistanceType}, this returns either the apogee (furthest distance)
* or the perigee (closest distance) that occurs on or after the given reference date.
*
* @param type the distance type to calculate (APOGEE or PERIGEE)
* @param julianDate the reference Julian date from which to search forward
* @return the Julian date of the requested lunar distance extreme
*/
private static double getApogeePerigee(DistanceType type, double julianDate) {
double k = floor((julianDate - JDE_0) / ANOMALISTIC_MONTH) + (type.equals(DistanceType.APOGEE) ? 0.5 : 0) - 1;
double jd = 0;
do {
double t = k / 1325.55;
double t2 = t * t;
double t3 = t2 * t;
double t4 = t3 * t;
double d = toRadians(171.9179 + 335.9106046 * k - .010025 * t2 - .00001156 * t3 + .000000055 * t4);
double m = toRadians(347.3477 + 27.1577721 * k - .0008323 * t2 - .000001 * t3);
double f = toRadians(316.6109 + 364.5287911 * k - .0125131 * t2 - .0000148 * t3);
jd = JDE_0 + ANOMALISTIC_MONTH * k - .0006886 * t2 - .000001098 * t3 + .0000000052 * t2;
if (DistanceType.APOGEE.equals(type)) {
jd += .4392 * sin(2 * d) + .0684 * sin(4 * d) + (.0456 - .00011 * t) * sin(m)
+ (.0426 - .00011 * t) * sin(2 * d - m) + .0212 * sin(2 * f);
jd += -.0189 * sin(d) + .0144 * sin(6 * d) + .0113 * sin(4 * d - m) + .0047 * sin(2 * d + 2 * f)
+ .0036 * sin(d + m) + .0035 * sin(8 * d) + .0034 * sin(6 * d - m) - .0034 * sin(2 * d - 2 * f)
+ .0022 * sin(2 * d - 2 * m) - .0017 * sin(3 * d);
jd += .0013 * sin(4 * d + 2 * f) + .0011 * sin(8 * d - m) + .001 * sin(4 * d - 2 * m)
+ .0009 * sin(10 * d) + .0007 * sin(3 * d + m) + .0006 * sin(2 * m) + .0005 * sin(2 * d + m)
+ .0005 * sin(2 * d + 2 * m) + .0004 * sin(6 * d + 2 * f);
jd += .0004 * sin(6 * d - 2 * m) + .0004 * sin(10 * d - m) - .0004 * sin(5 * d)
- .0004 * sin(4 * d - 2 * f) + .0003 * sin(2 * f + m) + .0003 * sin(12 * d)
+ .0003 * sin(2 * d + 2 * f - m) - .0003 * sin(d - m);
} else if (DistanceType.PERIGEE.equals(type)) {
jd += -1.6769 * sin(2 * d) + .4589 * sin(4 * d) - .1856 * sin(6 * d) + .0883 * sin(8 * d);
jd += -(.0773 + .00019 * t) * sin(2 * d - m) + (.0502 - .00013 * t) * sin(m) - .046 * sin(10 * d)
+ (.0422 - .00011 * t) * sin(4 * d - m) - .0256 * sin(6 * d - m) + .0253 * sin(12 * d)
+ .0237 * sin(d);
jd += .0162 * sin(8 * d - m) - .0145 * sin(14 * d) + .0129 * sin(2 * f) - .0112 * sin(3 * d)
- .0104 * sin(10 * d - m) + .0086 * sin(16 * d) + .0069 * sin(12 * d - m) + .0066 * sin(5 * d)
- .0053 * sin(2 * d + 2 * f);
jd += -.0052 * sin(18 * d) - .0046 * sin(14 * d - m) - .0041 * sin(7 * d) + .004 * sin(2 * d + m)
+ .0032 * sin(20 * d) - .0032 * sin(d + m) + .0031 * sin(16 * d - m);
jd += -.0029 * sin(4 * d + m) - .0027 * sin(2 * d - 2 * m) + .0024 * sin(4 * d - 2 * m)
- .0021 * sin(6 * d - 2 * m) - .0021 * sin(22 * d) - .0021 * sin(18 * d - m);
jd += .0019 * sin(6 * d + m) - .0018 * sin(11 * d) - .0014 * sin(8 * d + m) - .0014 * sin(4 * d - 2 * f)
- .0014 * sin(6 * d - 2 * f) + .0014 * sin(3 * d + m) - .0014 * sin(5 * d + m)
+ .0013 * sin(13 * d);
jd += .0013 * sin(20 * d - m) + .0011 * sin(3 * d + 2 * m) - .0011 * sin(4 * d + 2 * f - 2 * m)
- .001 * sin(d + 2 * m) - .0009 * sin(22 * d - m) - .0008 * sin(4 * f)
+ .0008 * sin(6 * d - 2 * f) + .0008 * sin(2 * d - 2 * f + m);
jd += .0007 * sin(2 * m) + .0007 * sin(2 * f - m) + .0007 * sin(2 * d + 4 * f)
- .0006 * sin(2 * f - 2 * m) - .0006 * sin(2 * d - 2 * f + 2 * m) + .0006 * sin(24 * d)
+ .0005 * sin(4 * d - 4 * f) + .0005 * sin(2 * d + 2 * m) - .0004 * sin(d - m)
+ .0027 * sin(9 * d) + .0027 * sin(4 * d + 2 * f);
}
k += 1;
} while (jd < julianDate);
return jd;
}
}
@@ -15,12 +15,15 @@ package org.openhab.binding.astro.internal.job;
import static org.openhab.binding.astro.internal.AstroBindingConstants.*;
import static org.openhab.binding.astro.internal.job.Job.scheduleEvent;
import java.time.Instant;
import java.util.Calendar;
import java.util.Locale;
import java.util.Set;
import java.util.TimeZone;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.astro.internal.handler.AstroThingHandler;
import org.openhab.binding.astro.internal.model.DistanceType;
import org.openhab.binding.astro.internal.model.Eclipse;
import org.openhab.binding.astro.internal.model.Moon;
import org.openhab.binding.astro.internal.model.MoonPhase;
@@ -102,14 +105,11 @@ public final class DailyJobMoon extends AbstractJob {
}
});
cal = moon.getPerigee().getDate();
if (cal != null) {
scheduleEvent(handler, cal, EVENT_PERIGEE, EVENT_CHANNEL_ID_PERIGEE, false, zone, locale);
}
cal = moon.getApogee().getDate();
if (cal != null) {
scheduleEvent(handler, cal, EVENT_APOGEE, EVENT_CHANNEL_ID_APOGEE, false, zone, locale);
}
Set.of(DistanceType.APOGEE, DistanceType.PERIGEE).forEach(type -> {
if (moon.getDistanceType(type).getDate() instanceof Instant theMoment) {
scheduleEvent(handler, theMoment, type.toString(), type.eventName(), false, zone, locale);
}
});
} catch (Exception e) {
LOGGER.warn("The daily moon job execution for \"{}\" failed: {}", handler.getThing().getUID(),
e.getMessage());
@@ -18,6 +18,8 @@ import static org.openhab.binding.astro.internal.util.DateTimeUtils.*;
import java.lang.invoke.MethodHandles;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;
@@ -76,14 +78,26 @@ public interface Job extends SchedulerRunnable, Runnable {
* @param job the {@link Job} instance to schedule
* @param eventAt the {@link Instant} instance denoting scheduled instant
*/
static void schedule(AstroThingHandler astroHandler, Job job, Instant eventAt) {
try {
static void schedule(AstroThingHandler astroHandler, Job job, Instant eventAt, ZoneId zone) {
ZonedDateTime now = ZonedDateTime.now(zone);
ZonedDateTime eventZDT = eventAt.atZone(zone);
if (isSameDay(eventZDT, now) && isTimeGreaterEquals(eventZDT, now)) {
astroHandler.schedule(job, eventAt);
} catch (Exception ex) {
LOGGER.error("{}", ex.getMessage(), ex);
}
}
/**
* Schedules the provided {@link Job} instance
*
* @param astroHandler the {@link AstroThingHandler} instance
* @param job the {@link Job} instance to schedule
* @param eventAt the {@link Instant} instance denoting scheduled instant
*/
static void schedule(AstroThingHandler astroHandler, Job job, Instant eventAt) {
astroHandler.schedule(job, eventAt);
}
/**
* Schedules an {@link EventJob} instance
*
@@ -97,6 +111,19 @@ public interface Job extends SchedulerRunnable, Runnable {
scheduleEvent(astroHandler, eventAt, List.of(event), channelId, configAlreadyApplied, zone, locale);
}
/**
* Schedules an {@link EventJob} instance
*
* @param astroHandler the {@link AstroThingHandler} instance
* @param eventAt the {@link Instant} instance denoting scheduled instant
* @param event the event ID
* @param channelId the channel ID
*/
static void scheduleEvent(AstroThingHandler astroHandler, Instant eventAt, String event, String channelId,
boolean configAlreadyApplied, TimeZone zone, Locale locale) {
scheduleEvent(astroHandler, eventAt, List.of(event), channelId, configAlreadyApplied, zone, locale);
}
/**
* Schedules an {@link EventJob} instance
*
@@ -126,6 +153,35 @@ public interface Job extends SchedulerRunnable, Runnable {
schedule(astroHandler, new CompositeJob(astroHandler, jobs), instant, zone, locale);
}
/**
* Schedules an {@link EventJob} instance
*
* @param astroHandler the {@link AstroThingHandler} instance
* @param eventAt the {@link Instant} instance denoting scheduled instant
* @param events the event IDs to schedule
* @param channelId the channel ID
*/
static void scheduleEvent(AstroThingHandler astroHandler, Instant eventAt, List<String> events, String channelId,
boolean configAlreadyApplied, TimeZone zone, Locale locale) {
if (events.isEmpty()) {
return;
}
final Instant instant;
if (!configAlreadyApplied) {
final Channel channel = astroHandler.getThing().getChannel(channelId);
if (channel == null) {
LOGGER.warn("Cannot find channel '{}' for thing '{}'.", channelId, astroHandler.getThing().getUID());
return;
}
AstroChannelConfig config = channel.getConfiguration().as(AstroChannelConfig.class);
instant = applyConfig(eventAt, config);
} else {
instant = eventAt;
}
List<Job> jobs = events.stream().map(e -> new EventJob(astroHandler, channelId, e)).collect(toList());
schedule(astroHandler, new CompositeJob(astroHandler, jobs), instant, zone.toZoneId());
}
/**
* Schedules {@link Channel} events
*
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2010-2026 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.astro.internal.model;
import java.util.Locale;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Various types of observed distances
*
* @author Gaël L'hopital - Initial contribution
*/
@NonNullByDefault
public enum DistanceType {
APOGEE,
PERIGEE,
CURRENT;
public String eventName() {
return this.name().toLowerCase(Locale.ROOT) + "#event";
}
}
@@ -12,6 +12,11 @@
*/
package org.openhab.binding.astro.internal.model;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
@@ -21,14 +26,17 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
*/
@NonNullByDefault
public class Moon extends RiseSet implements Planet {
private final Map<DistanceType, MoonDistance> distances = new HashMap<>(DistanceType.values().length);
private MoonPhase phase = new MoonPhase();
private MoonDistance apogee = new MoonDistance();
private MoonDistance perigee = new MoonDistance();
private MoonDistance distance = new MoonDistance();
private Eclipse eclipse = new Eclipse(EclipseKind.PARTIAL, EclipseKind.TOTAL);
private Position position = new Position();
private Zodiac zodiac = Zodiac.NULL;
public Moon() {
EnumSet.allOf(DistanceType.class).forEach(d -> distances.put(d, MoonDistance.NULL));
}
/**
* Returns the moon phase.
*/
@@ -43,32 +51,26 @@ public class Moon extends RiseSet implements Planet {
this.phase = phase;
}
public MoonDistance getDistanceType(DistanceType type) {
return Objects.requireNonNull(distances.get(type));
}
/**
* Returns the apogee.
*/
public MoonDistance getApogee() {
return apogee;
}
/**
* Sets the apogee.
*/
public void setApogee(MoonDistance apogee) {
this.apogee = apogee;
return getDistanceType(DistanceType.APOGEE);
}
/**
* Returns the perigee.
*/
public MoonDistance getPerigee() {
return perigee;
return getDistanceType(DistanceType.PERIGEE);
}
/**
* Sets the perigee.
*/
public void setPerigee(MoonDistance perigee) {
this.perigee = perigee;
public void setDistance(DistanceType type, MoonDistance moonDistance) {
distances.put(type, moonDistance);
}
/**
@@ -89,14 +91,7 @@ public class Moon extends RiseSet implements Planet {
* Returns the current distance.
*/
public MoonDistance getDistance() {
return distance;
}
/**
* Sets the current distance.
*/
public void setDistance(MoonDistance distance) {
this.distance = distance;
return getDistanceType(DistanceType.CURRENT);
}
/**
@@ -12,55 +12,53 @@
*/
package org.openhab.binding.astro.internal.model;
import static org.openhab.core.library.unit.MetricPrefix.KILO;
import static org.openhab.core.library.unit.SIUnits.METRE;
import java.util.Calendar;
import java.time.Instant;
import javax.measure.quantity.Length;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.astro.internal.util.DateTimeUtils;
import org.openhab.core.library.types.QuantityType;
/**
* Holds a distance informations.
* Holds a distance information.
*
* @author Gerhard Riegler - Initial contribution
* @author Christoph Weitkamp - Introduced UoM
* @author Gaël L'hopital - Use Instant, made immutable
*/
@NonNullByDefault
public class MoonDistance {
public static final MoonDistance NULL = new MoonDistance();
private @Nullable Calendar date;
private double distance;
private final @Nullable Instant date;
private final double distance;
private MoonDistance() {
this.date = null;
this.distance = Double.NaN;
}
public MoonDistance(double distanceJd, double distance) {
this.date = DateTimeUtils.jdToInstant(distanceJd);
this.distance = distance;
}
/**
* Returns the date of the calculated distance.
*/
@Nullable
public Calendar getDate() {
public Instant getDate() {
return date;
}
/**
* Sets the date of the calculated distance.
* Returns the distance in metres.
*/
public void setDate(@Nullable Calendar date) {
this.date = date;
}
/**
* Returns the distance in kilometers.
*/
public QuantityType<Length> getDistance() {
return new QuantityType<>(distance, KILO(METRE));
}
/**
* Sets the distance in kilometers.
*/
public void setDistance(double kilometer) {
this.distance = kilometer;
public @Nullable QuantityType<Length> getDistance() {
return Double.isNaN(distance) ? null : new QuantityType<>(distance, METRE);
}
}
@@ -27,6 +27,9 @@ public class AstroConstants {
public static final double TROPICAL_YEAR_SECONDS = TROPICAL_YEAR_DAYS * SECONDS_PER_DAY;
public static final double SOLAR_MEAN_MOTION_PER_SECOND = MathUtils.TWO_PI / AstroConstants.TROPICAL_YEAR_SECONDS;
/** Constant term of the E5 angle. */
public static final double E05_0 = 357.52910918;
/** Constructor */
private AstroConstants() {
throw new IllegalAccessError("Non-instantiable");
@@ -13,6 +13,7 @@
package org.openhab.binding.astro.internal.util;
import java.time.Instant;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Calendar;
import java.util.Locale;
@@ -205,6 +206,14 @@ public class DateTimeUtils {
&& cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR);
}
/**
* Returns true, if two ZonedDateTime objects are on the same day ignoring time.
*/
public static boolean isSameDay(@Nullable ZonedDateTime zdt1, @Nullable ZonedDateTime zdt2) {
return zdt1 != null && zdt2 != null
&& zdt1.toLocalDate().equals(zdt2.withZoneSameInstant(zdt1.getZone()).toLocalDate());
}
/**
* Returns the next Calendar from today.
*/
@@ -245,6 +254,15 @@ public class DateTimeUtils {
return truncCal1.getTimeInMillis() >= truncCal2.getTimeInMillis();
}
/**
* Returns true, if inst1 is greater or equal than inst2, ignoring seconds.
*/
public static boolean isTimeGreaterEquals(ZonedDateTime inst1, ZonedDateTime inst2) {
ZonedDateTime truncInst1 = inst1.truncatedTo(ChronoUnit.MINUTES);
ZonedDateTime truncInst2 = inst2.truncatedTo(ChronoUnit.MINUTES);
return !truncInst1.isBefore(truncInst2);
}
public static Calendar getAdjustedEarliest(Calendar cal, AstroChannelConfig config) {
int minutes = getMinutesFromTime(config.earliest);
// MainUI sets earliest to 00:00 if unconfigured, which is why zero must be treated as such
@@ -113,6 +113,7 @@
<item-type>DateTime</item-type>
<label>Start Time</label>
<description>The start time of the event</description>
<category>calendar</category>
<tags>
<tag>Calculation</tag>
<tag>Timestamp</tag>
@@ -125,6 +126,7 @@
<item-type>DateTime</item-type>
<label>End Time</label>
<description>The end time of the event</description>
<category>calendar</category>
<tags>
<tag>Calculation</tag>
<tag>Timestamp</tag>
@@ -312,6 +314,7 @@
<item-type>DateTime</item-type>
<label>Total Eclipse</label>
<description>The DateTime of the next total eclipse</description>
<category>calendar</category>
<tags>
<tag>Calculation</tag>
<tag>Timestamp</tag>
@@ -323,6 +326,7 @@
<item-type>DateTime</item-type>
<label>Partial Eclipse</label>
<description>The DateTime of the next partial eclipse</description>
<category>calendar</category>
<tags>
<tag>Calculation</tag>
<tag>Timestamp</tag>
@@ -334,6 +338,7 @@
<item-type>DateTime</item-type>
<label>Ring Eclipse</label>
<description>The DateTime of the next ring eclipse</description>
<category>calendar</category>
<tags>
<tag>Calculation</tag>
<tag>Timestamp</tag>
@@ -411,6 +416,7 @@
<item-type>DateTime</item-type>
<label>First Quarter</label>
<description>The DateTime the moon is in the first quarter</description>
<category>calendar</category>
<tags>
<tag>Calculation</tag>
<tag>Timestamp</tag>
@@ -422,6 +428,7 @@
<item-type>DateTime</item-type>
<label>Third Quarter</label>
<description>The DateTime the moon is in the third quarter</description>
<category>calendar</category>
<tags>
<tag>Calculation</tag>
<tag>Timestamp</tag>
@@ -433,6 +440,7 @@
<item-type>DateTime</item-type>
<label>Full Moon</label>
<description>The DateTime for full moon</description>
<category>calendar</category>
<tags>
<tag>Calculation</tag>
<tag>Timestamp</tag>
@@ -444,6 +452,7 @@
<item-type>DateTime</item-type>
<label>New Moon</label>
<description>The DateTime for new moon</description>
<category>calendar</category>
<tags>
<tag>Calculation</tag>
<tag>Timestamp</tag>
@@ -570,6 +579,7 @@
<item-type>DateTime</item-type>
<label>Date</label>
<description>The DateTime when the distance is reached</description>
<category>calendar</category>
<tags>
<tag>Calculation</tag>
<tag>Timestamp</tag>
@@ -48,7 +48,6 @@ public class MoonCalcTest {
private static final double AMSTERDAM_LONGITUDE = 4.8978293;
private static final int ACCURACY_IN_MILLIS = 5 * 60 * 1000;
private static final int ACCURACY_IN_KILOMETRES = 4;
private static final double ACCURACY_IN_DEGREE = 0.3;
private @Nullable MoonCalc moonCalc;
@@ -79,33 +78,6 @@ public class MoonCalcTest {
assertNull(moon.getPhase().getName());
}
@Test
public void testGetMoonInfoForApogeeAccuracy() {
Moon moon = Objects.requireNonNull(moonCalc).getMoonInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE,
TIME_ZONE, Locale.ROOT);
// expected result from haevens-above.com is 406,391 km @ 04 March 2019 12:27
assertEquals(406391, moon.getApogee().getDistance().doubleValue(), ACCURACY_IN_KILOMETRES);
Calendar apogeeDate = moon.getApogee().getDate();
assertNotNull(apogeeDate);
assertEquals(MoonCalcTest.newCalendar(2019, Calendar.MARCH, 4, 12, 27, TIME_ZONE).getTimeInMillis(),
apogeeDate.getTimeInMillis(), ACCURACY_IN_MILLIS);
}
@Test
public void testGetMoonInfoForPerigeeAccuracy() {
Moon moon = Objects.requireNonNull(moonCalc).getMoonInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE,
TIME_ZONE, Locale.ROOT);
// expected result from haevens-above.com is 359,377 km @ 19 February 2019 20:44
assertEquals(359377, moon.getPerigee().getDistance().doubleValue(), ACCURACY_IN_KILOMETRES);
Calendar perigeeDate = moon.getPerigee().getDate();
assertNotNull(perigeeDate);
assertEquals(MoonCalcTest.newCalendar(2019, Calendar.MARCH, 19, 20, 48, TIME_ZONE).getTimeInMillis(),
perigeeDate.getTimeInMillis(), ACCURACY_IN_MILLIS);
}
@Test
public void testGetMoonInfoForRiseAccuracy() {
Moon moon = Objects.requireNonNull(moonCalc).getMoonInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE,
@@ -113,7 +85,7 @@ public class MoonCalcTest {
Calendar riseStart = moon.getRise().getStart();
assertNotNull(riseStart);
// expected result from haevens-above.com is 03:00
// expected result from heavens-above.com is 03:00
assertEquals(MoonCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 3, 0, TIME_ZONE).getTimeInMillis(),
riseStart.getTimeInMillis(), ACCURACY_IN_MILLIS);
}
@@ -125,7 +97,7 @@ public class MoonCalcTest {
Calendar setStart = moon.getSet().getStart();
assertNotNull(setStart);
// expected result from haevens-above.com is 11:35
// expected result from heavens-above.com is 11:35
assertEquals(MoonCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 11, 35, TIME_ZONE).getTimeInMillis(),
setStart.getTimeInMillis(), ACCURACY_IN_MILLIS);
}
@@ -137,22 +109,11 @@ public class MoonCalcTest {
Moon moon = moonCalc.getMoonInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, TIME_ZONE, Locale.ROOT);
moonCalc.setPositionalInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, moon, TIME_ZONE, Locale.ROOT);
// expected result from haevens-above.com is Azimuth: 100.5, altitude -17
// expected result from heavens-above.com is Azimuth: 100.5, altitude -17
assertEquals(100.5, moon.getPosition().getAzimuth().doubleValue(), ACCURACY_IN_DEGREE);
assertEquals(-17, moon.getPosition().getElevation().doubleValue(), ACCURACY_IN_DEGREE);
}
@Test
public void testGetMoonInfoForMoonDistanceAccuracy() {
MoonCalc moonCalc = this.moonCalc;
assertNotNull(moonCalc);
Moon moon = moonCalc.getMoonInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, TIME_ZONE, Locale.ROOT);
moonCalc.setPositionalInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, moon, TIME_ZONE, Locale.ROOT);
// expected result from haevens-above.com is 392612 km
assertEquals(392612, moon.getDistance().getDistance().doubleValue(), ACCURACY_IN_KILOMETRES);
}
@Test
public void testGetMoonInfoForMoonPhaseAccuracy() {
MoonCalc moonCalc = this.moonCalc;
@@ -0,0 +1,130 @@
/*
* Copyright (c) 2010-2026 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.astro.internal.calc;
import static org.junit.jupiter.api.Assertions.*;
import static org.openhab.core.library.unit.MetricPrefix.KILO;
import static org.openhab.core.library.unit.SIUnits.METRE;
import java.time.Instant;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.Test;
import org.openhab.binding.astro.internal.model.DistanceType;
import org.openhab.binding.astro.internal.model.MoonDistance;
import org.openhab.binding.astro.internal.util.DateTimeUtils;
/***
* Specific unit tests to check if {@link MoonCalc} generates correct data for
* Amsterdam city on 27 February 2019. In particular the following cases are
* covered:
* <ul>
* <li>checks if generated data are the same (with some accuracy) as produced by
* heavens-above.com</li>
* </ul>
*
* @author Leo Siepel - Initial contribution
* @see <a href="https://www.heavens-above.com/Moon.aspx">Heavens Above Moon</a>
*/
@NonNullByDefault
public class MoonDistanceCalcTest {
private static final TimeZone TIME_ZONE = TimeZone.getTimeZone("Europe/Amsterdam");
private static final Calendar FEB_27_2019 = newCalendar(2019, Calendar.FEBRUARY, 27, 1, 0, TIME_ZONE);
private static final int ACCURACY_IN_MILLIS = 5 * 60 * 1000;
private static final int ACCURACY_IN_KILOMETRES = 4;
@Test
public void testGetMoonInfoForApogeeAccuracy() {
double jdate = DateTimeUtils.dateToJulianDate(FEB_27_2019);
MoonDistance distance = MoonDistanceCalc.get(DistanceType.APOGEE, jdate);
// expected result from heavens-above.com is 406,391 km @ 04 March 2019 12:27
var apogeeDistance = distance.getDistance();
assertNotNull(apogeeDistance);
var kmDistance = apogeeDistance.toUnit(KILO(METRE));
assertNotNull(kmDistance);
assertEquals(406391, kmDistance.doubleValue(), ACCURACY_IN_KILOMETRES);
Instant apogeeDate = distance.getDate();
assertNotNull(apogeeDate);
assertEquals(newCalendar(2019, Calendar.MARCH, 4, 12, 27, TIME_ZONE).getTimeInMillis(),
apogeeDate.toEpochMilli(), ACCURACY_IN_MILLIS);
}
@Test
public void testGetMoonInfoForPerigeeAccuracy() {
double jdate = DateTimeUtils.dateToJulianDate(FEB_27_2019);
MoonDistance distance = MoonDistanceCalc.get(DistanceType.PERIGEE, jdate);
// expected result from heavens-above.com is 359,377 km @ 19 February 2019 20:44
var perigeeDistance = distance.getDistance();
assertNotNull(perigeeDistance);
var kmDistance = perigeeDistance.toUnit(KILO(METRE));
assertNotNull(kmDistance);
assertEquals(359377, kmDistance.doubleValue(), ACCURACY_IN_KILOMETRES);
Instant perigeeDate = distance.getDate();
assertNotNull(perigeeDate);
assertEquals(newCalendar(2019, Calendar.MARCH, 19, 20, 48, TIME_ZONE).getTimeInMillis(),
perigeeDate.toEpochMilli(), ACCURACY_IN_MILLIS);
}
@Test
public void testGetMoonInfoForMoonDistanceAccuracy() {
double jdate = DateTimeUtils.dateToJulianDate(FEB_27_2019);
MoonDistance distance = MoonDistanceCalc.calculate(jdate);
// expected result from heavens-above.com is 392612 km
var currentDistance = distance.getDistance();
assertNotNull(currentDistance);
var kmDistance = currentDistance.toUnit(KILO(METRE));
assertNotNull(kmDistance);
assertEquals(392612, kmDistance.doubleValue(), ACCURACY_IN_KILOMETRES);
}
/***
* Constructs a <code>GregorianCalendar</code> with the given date and time set
* for the provided time zone.
*
* @param year
* the value used to set the <code>YEAR</code> calendar field in the
* calendar.
* @param month
* the value used to set the <code>MONTH</code> calendar field in the
* calendar. Month value is 0-based. e.g., 0 for January.
* @param dayOfMonth
* the value used to set the <code>DAY_OF_MONTH</code> calendar field
* in the calendar.
* @param hourOfDay
* the value used to set the <code>HOUR_OF_DAY</code> calendar field
* in the calendar.
* @param minute
* the value used to set the <code>MINUTE</code> calendar field in
* the calendar.
* @param zone
* the given time zone.
* @return a {@link Calendar} set to the given date and time in the specified
* time zone, truncated to minute precision.
*/
private static Calendar newCalendar(int year, int month, int dayOfMonth, int hourOfDay, int minute, TimeZone zone) {
Calendar result = new GregorianCalendar(zone, Locale.ROOT);
result.set(year, month, dayOfMonth, hourOfDay, minute);
return DateTimeUtils.truncateToMinute(result);
}
}
@@ -36,7 +36,7 @@ import org.openhab.binding.astro.internal.util.DateTimeUtils;
* covered:
* <ul>
* <li>checks if generated data are the same (with some accuracy) as produced by
* haevens-above.com</li>
* heavens-above.com</li>
* <li>checks if the generated {@link Sun#getAllRanges()} are consistent with
* each other</li>
* </ul>
@@ -102,7 +102,7 @@ public class SunCalcTest {
assertNotNull(range);
Calendar cal = range.getStart();
assertNotNull(cal);
// expected result from haevens-above.com is 27 Feb 2019 05:39 till 06:18
// expected result from heavens-above.com is 27 Feb 2019 05:39 till 06:18
assertEquals(SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 5, 39, AMSTERDAM_TIME_ZONE).getTimeInMillis(),
cal.getTimeInMillis(), ACCURACY_IN_MILLIS);
cal = range.getEnd();
@@ -120,7 +120,7 @@ public class SunCalcTest {
assertNotNull(range);
Calendar cal = range.getStart();
assertNotNull(cal);
// expected result from haevens-above.com is 27 Feb 2019 06:18 till 06:58
// expected result from heavens-above.com is 27 Feb 2019 06:18 till 06:58
assertEquals(SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 6, 18, AMSTERDAM_TIME_ZONE).getTimeInMillis(),
cal.getTimeInMillis(), ACCURACY_IN_MILLIS);
cal = range.getEnd();
@@ -138,7 +138,7 @@ public class SunCalcTest {
assertNotNull(range);
Calendar cal = range.getStart();
assertNotNull(cal);
// expected result from haevens-above.com is 27 Feb 2019 06:58 till 07:32
// expected result from heavens-above.com is 27 Feb 2019 06:58 till 07:32
assertEquals(SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 6, 58, AMSTERDAM_TIME_ZONE).getTimeInMillis(),
cal.getTimeInMillis(), ACCURACY_IN_MILLIS);
cal = range.getEnd();
@@ -156,7 +156,7 @@ public class SunCalcTest {
assertNotNull(range);
Calendar cal = range.getStart();
assertNotNull(cal);
// expected result from haevens-above.com is 27 Feb 2019 07:32
// expected result from heavens-above.com is 27 Feb 2019 07:32
assertEquals(SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 7, 32, AMSTERDAM_TIME_ZONE).getTimeInMillis(),
cal.getTimeInMillis(), ACCURACY_IN_MILLIS);
}
@@ -170,7 +170,7 @@ public class SunCalcTest {
assertNotNull(range);
Calendar cal = range.getStart();
assertNotNull(cal);
// expected result from haevens-above.com is 27 Feb 2019 12:54
// expected result from heavens-above.com is 27 Feb 2019 12:54
assertEquals(
SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 12, 54, AMSTERDAM_TIME_ZONE).getTimeInMillis(),
cal.getTimeInMillis(), ACCURACY_IN_MILLIS);
@@ -185,7 +185,7 @@ public class SunCalcTest {
assertNotNull(range);
Calendar cal = range.getStart();
assertNotNull(cal);
// expected result from haevens-above.com is 27 Feb 2019 18:15
// expected result from heavens-above.com is 27 Feb 2019 18:15
assertEquals(
SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 18, 15, AMSTERDAM_TIME_ZONE).getTimeInMillis(),
cal.getTimeInMillis(), ACCURACY_IN_MILLIS);
@@ -200,7 +200,7 @@ public class SunCalcTest {
assertNotNull(range);
Calendar cal = range.getStart();
assertNotNull(cal);
// expected result from haevens-above.com is 27 Feb 2019 18:15 till 18:50
// expected result from heavens-above.com is 27 Feb 2019 18:15 till 18:50
assertEquals(
SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 18, 15, AMSTERDAM_TIME_ZONE).getTimeInMillis(),
cal.getTimeInMillis(), ACCURACY_IN_MILLIS);
@@ -220,7 +220,7 @@ public class SunCalcTest {
assertNotNull(range);
Calendar cal = range.getStart();
assertNotNull(cal);
// expected result from haevens-above.com is 27 Feb 2019 18:50 till 19:29
// expected result from heavens-above.com is 27 Feb 2019 18:50 till 19:29
assertEquals(
SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 18, 50, AMSTERDAM_TIME_ZONE).getTimeInMillis(),
cal.getTimeInMillis(), ACCURACY_IN_MILLIS);
@@ -240,7 +240,7 @@ public class SunCalcTest {
assertNotNull(range);
Calendar cal = range.getStart();
assertNotNull(cal);
// expected result from haevens-above.com is 27 Feb 2019 19:29 till 20:09
// expected result from heavens-above.com is 27 Feb 2019 19:29 till 20:09
assertEquals(
SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 19, 29, AMSTERDAM_TIME_ZONE).getTimeInMillis(),
cal.getTimeInMillis(), ACCURACY_IN_MILLIS);
@@ -34,7 +34,7 @@ import org.openhab.binding.astro.internal.util.DateTimeUtils;
* covered:
* <ul>
* <li>checks if generated data are the same (with some accuracy) as produced by
* haevens-above.com</li>
* heavens-above.com</li>
* </ul>
*
* @author Leo Siepel - Initial contribution