diff --git a/.gitignore b/.gitignore index a6f89c2..0643ce7 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -/target/ \ No newline at end of file +/target/ +/nbproject/ \ No newline at end of file diff --git a/src/main/java/ua/net/uid/utils/time/DailyEquation.java b/src/main/java/ua/net/uid/utils/time/DailyEquation.java new file mode 100644 index 0000000..4b31cdb --- /dev/null +++ b/src/main/java/ua/net/uid/utils/time/DailyEquation.java @@ -0,0 +1,105 @@ +package ua.net.uid.utils.time; + +import java.util.Calendar; + +/** + * + * + * https://web.archive.org/web/20161202180207/http://williams.best.vwh.net/sunrise_sunset_algorithm.htm + * http://edwilliams.org/sunrise_sunset_algorithm.htm + * https://edwilliams.org/sunrise_sunset_example.htm + * + * https://github.com/KlausBrunner/solarpositioning + * https://github.com/mikereedell/sunrisesunsetlib-java + * https://github.com/shred/commons-suncalc + * https://gist.github.com/Tafkas/4742250 + * + * https://github.com/caarmen/SunriseSunset + * http://users.electromagnetic.net/bu/astro/sunrise-set.php + * + * + * https://www.aa.quae.nl/en/reken/zonpositie.html + * + * TODO: переделать под java.time + * + * @author nightfall + */ +public class DailyEquation { + public static DailyEvents getSunEvents(double latitude, double longitude, Calendar calendar, Zenith zenith) { + return getSunEvents(latitude, longitude, calendar, zenith.getDegrees()); + } + + public static DailyEvents getSunEvents(double latitude, double longitude, Calendar calendar, double zenith) { + longitude /= 15; + int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR); + + double sunrizeTime = calculateEvent(latitude, longitude, zenith, dayOfYear, true); + double sunsetTime = calculateEvent(latitude, longitude, zenith, dayOfYear, false); + + if (sunrizeTime == Double.NEGATIVE_INFINITY || sunsetTime == Double.NEGATIVE_INFINITY) { // the sun never rises on this location (on the specified date) + return new DailyEvents(null, null, DailyEventType.POLAR_NIGHT); + } else if (sunrizeTime == Double.POSITIVE_INFINITY || sunsetTime == Double.POSITIVE_INFINITY) { // the sun never sets on this location (on the specified date) + return new DailyEvents(null, null, DailyEventType.POLAR_DAY); + } else { + return new DailyEvents(convertDate(calendar, sunrizeTime), convertDate(calendar, sunsetTime), DailyEventType.NORMAL_DAY); + } + } + + protected static double calculateEvent(double latitude, double baseLongitudeHour, double zenith, int dayOfYear, boolean rising) { + //t = ((rising ? 6 : 18) - lngHour) / 24 + dayOfYear; + double longitudeHour = ((rising ? 6 : 18) - baseLongitudeHour) / 24 + dayOfYear; + // M = 0.9856 * t - 3.289; + double meanAnomaly = 0.9856 * longitudeHour - 3.289; + double meanAnomalyRadians = Math.toRadians(meanAnomaly); + // L = M + (1.916 * sin(M)) + (0.020 * sin(2 * M)) + 282.634 + double sunTrueLong = meanAnomaly + (1.916 * Math.sin(meanAnomalyRadians)) + (0.020 * Math.sin(2 * meanAnomalyRadians)) + 282.634; // L + if (sunTrueLong > 360) sunTrueLong -= 360; + + // sinDec = 0.39782 * sin(L); + double sinSunDeclination = 0.39782 * Math.sin(Math.toRadians(sunTrueLong)); + // cosDec = cos(asin(sinDec)); + double cosineSunDeclination = Math.cos(Math.asin(sinSunDeclination)); + // cosH = (cos(zenith) - (sinDec * sin(latitude))) / (cosDec * cos(latitude)); + double latitudeRadians = Math.toRadians(latitude); + double cosineSunLocalHour = (Math.cos(Math.toRadians(zenith)) - sinSunDeclination * Math.sin(latitudeRadians)) + / (cosineSunDeclination * Math.cos(latitudeRadians)); + + if (cosineSunLocalHour > 1) return Double.NEGATIVE_INFINITY; // the sun never rises on this location (on the specified date) + if (cosineSunLocalHour < -1) return Double.POSITIVE_INFINITY; // the sun never sets on this location (on the specified date) + + // H = (rising ? 360 - acos(cosH) : acos(cosH)) / 15; + double sunLocalHour = Math.toDegrees(Math.acos(cosineSunLocalHour)); + sunLocalHour = (rising ? 360 - sunLocalHour : sunLocalHour) / 15; + + // RA = atan(0.91764 * tan(L)); // RA + //double rightAscension = Math.atan(Math.toRadians(0.91764 * Math.toDegrees( Math.tan(Math.toRadians(sunTrueLong)) ))); + double rightAscension = Math.toDegrees(Math.atan(Math.toRadians(0.91764 * Math.toDegrees( Math.tan(Math.toRadians(sunTrueLong)) )))); + + //--- //RA potentially needs to be adjusted into the range [0,360) by adding/subtracting 360 + //--- if (rightAscension < 0) { rightAscension += 360; } else if (rightAscension > 360) { rightAscension -= 360; } + // RA = (RA + (floor(L/90) - floor(RA/90)) * 90) / 15; + rightAscension = (rightAscension + (Math.floor(sunTrueLong / 90) - Math.floor(rightAscension / 90)) * 90) / 15; + + // T = H + RA - (0.06571 * t) - 6.622 + double localMeanTime = sunLocalHour + rightAscension - (longitudeHour * 0.06571) - 6.622; // T + + // UT = T - lngHour + return localMeanTime - baseLongitudeHour; + } + + protected static long convertDate(Calendar calendar, double utcTime) { + // localT = UT + localOffset + int time = (int)(utcTime * 3600000) + calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET); + // UT potentially needs to be adjusted into the range [0,24) by adding/subtracting 24 + //if (utcTime >= 24.) utcTime -= 24; else if (utcTime < 0) utcTime += 24; + if (time >= DAYMSEC) time -= DAYMSEC; else if (time < 0) time += DAYMSEC; + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + calendar.add(Calendar.MILLISECOND, time); + return calendar.getTimeInMillis(); + } + + private static final int DAYMSEC = 24 * 60 * 60 * 1000; +} diff --git a/src/main/java/ua/net/uid/utils/time/DailyEventType.java b/src/main/java/ua/net/uid/utils/time/DailyEventType.java new file mode 100644 index 0000000..26bab43 --- /dev/null +++ b/src/main/java/ua/net/uid/utils/time/DailyEventType.java @@ -0,0 +1,17 @@ +package ua.net.uid.utils.time; + +public enum DailyEventType { + NORMAL_DAY("normal"), + POLAR_NIGHT("night"), + POLAR_DAY("day"); + + private final String title; + + DailyEventType(String title) { + this.title = title; + } + + public String getTitle() { + return title; + } +} diff --git a/src/main/java/ua/net/uid/utils/time/DailyEvents.java b/src/main/java/ua/net/uid/utils/time/DailyEvents.java new file mode 100644 index 0000000..a88e146 --- /dev/null +++ b/src/main/java/ua/net/uid/utils/time/DailyEvents.java @@ -0,0 +1,25 @@ +package ua.net.uid.utils.time; + +public class DailyEvents { + private final Long sunrise; + private final Long sunset; + private final DailyEventType type; + + DailyEvents(Long sunrise, Long sunset, DailyEventType type) { + this.sunrise = sunrise; + this.sunset = sunset; + this.type = type; + } + + public Long getSunrise() { + return sunrise; + } + + public Long getSunset() { + return sunset; + } + + public DailyEventType getType() { + return type; + } +} diff --git a/src/main/java/ua/net/uid/utils/time/Zenith.java b/src/main/java/ua/net/uid/utils/time/Zenith.java new file mode 100644 index 0000000..5317e8d --- /dev/null +++ b/src/main/java/ua/net/uid/utils/time/Zenith.java @@ -0,0 +1,18 @@ +package ua.net.uid.utils.time; + +public enum Zenith { + ASTRONOMICAL(108.), // Astronomical sunrise/set is when the sun is 18 degrees below the horizon. + NAUTICAL(102.), // Nautical sunrise/set is when the sun is 12 degrees below the horizon. + CIVIL(96.), // Civil sunrise/set (dawn/dusk) is when the sun is 6 degrees below the horizon. + OFFICIAL(90.8333); // Official sunrise/set is when the sun is 50' below the horizon. + + private final double degrees; + + Zenith(double degrees) { + this.degrees = degrees; + } + + public double getDegrees() { + return degrees; + } +} diff --git a/src/main/java/ua/net/uid/utils/tools/DailyEquation.java b/src/main/java/ua/net/uid/utils/tools/DailyEquation.java deleted file mode 100644 index 90eefeb..0000000 --- a/src/main/java/ua/net/uid/utils/tools/DailyEquation.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2019 nightfall. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ua.net.uid.utils.tools; - -import java.util.Calendar; - -/** - * - * - * https://web.archive.org/web/20161202180207/http://williams.best.vwh.net/sunrise_sunset_algorithm.htm - * http://edwilliams.org/sunrise_sunset_algorithm.htm - * https://edwilliams.org/sunrise_sunset_example.htm - * - * https://github.com/KlausBrunner/solarpositioning - * https://github.com/mikereedell/sunrisesunsetlib-java - * https://github.com/shred/commons-suncalc - * https://gist.github.com/Tafkas/4742250 - * - * https://github.com/caarmen/SunriseSunset - * http://users.electromagnetic.net/bu/astro/sunrise-set.php - * - * - * https://www.aa.quae.nl/en/reken/zonpositie.html - * - * @author nightfall - */ -public class DailyEquation { - //////////////////////////////////////////////////////////////////////////// - public enum Zenith { - ASTRONOMICAL(108.), // Astronomical sunrise/set is when the sun is 18 degrees below the horizon. - NAUTICAL(102.), // Nautical sunrise/set is when the sun is 12 degrees below the horizon. - CIVIL(96.), // Civil sunrise/set (dawn/dusk) is when the sun is 6 degrees below the horizon. - OFFICIAL(90.8333); // Official sunrise/set is when the sun is 50' below the horizon. - - private final double degrees; - Zenith(double degrees) { this.degrees = degrees; } - public double getDegrees() { return degrees; } - } - //////////////////////////////////////////////////////////////////////////// - public enum Type { - NORMAL_DAY("normal"), - POLAR_NIGHT("night"), - POLAR_DAY("day"); - private final String title; - Type(String title) { this.title = title; } - public String getTitle() { return title; } - } - //////////////////////////////////////////////////////////////////////////// - public static class Events { - private final Long sunrise; - private final Long sunset; - private final Type type; - Events(Long sunrise, Long sunset, Type type) { - this.sunrise = sunrise; - this.sunset = sunset; - this.type = type; - } - public Long getSunrise() { return sunrise; } - public Long getSunset() { return sunset; } - public Type getType() { return type; } - } - //////////////////////////////////////////////////////////////////////////// - public static Events getSunEvents(double latitude, double longitude, Calendar calendar, Zenith zenith) { - return getSunEvents(latitude, longitude, calendar, zenith.getDegrees()); - } - public static Events getSunEvents(double latitude, double longitude, Calendar calendar, double zenith) { - longitude /= 15; - int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR); - - double sunrizeTime = calculateEvent(latitude, longitude, zenith, dayOfYear, true); - double sunsetTime = calculateEvent(latitude, longitude, zenith, dayOfYear, false); - - if (sunrizeTime == Double.NEGATIVE_INFINITY || sunsetTime == Double.NEGATIVE_INFINITY) { // the sun never rises on this location (on the specified date) - return new Events(null, null, Type.POLAR_NIGHT); - } else if (sunrizeTime == Double.POSITIVE_INFINITY || sunsetTime == Double.POSITIVE_INFINITY) { // the sun never sets on this location (on the specified date) - return new Events(null, null, Type.POLAR_DAY); - } else { - return new Events(convertDate(calendar, sunrizeTime), convertDate(calendar, sunsetTime), Type.NORMAL_DAY); - } - } - - protected static double calculateEvent(double latitude, double baseLongitudeHour, double zenith, int dayOfYear, boolean rising) { - //t = ((rising ? 6 : 18) - lngHour) / 24 + dayOfYear; - double longitudeHour = ((rising ? 6 : 18) - baseLongitudeHour) / 24 + dayOfYear; - // M = 0.9856 * t - 3.289; - double meanAnomaly = 0.9856 * longitudeHour - 3.289; - double meanAnomalyRadians = Math.toRadians(meanAnomaly); - // L = M + (1.916 * sin(M)) + (0.020 * sin(2 * M)) + 282.634 - double sunTrueLong = meanAnomaly + (1.916 * Math.sin(meanAnomalyRadians)) + (0.020 * Math.sin(2 * meanAnomalyRadians)) + 282.634; // L - if (sunTrueLong > 360) sunTrueLong -= 360; - - // sinDec = 0.39782 * sin(L); - double sinSunDeclination = 0.39782 * Math.sin(Math.toRadians(sunTrueLong)); - // cosDec = cos(asin(sinDec)); - double cosineSunDeclination = Math.cos(Math.asin(sinSunDeclination)); - // cosH = (cos(zenith) - (sinDec * sin(latitude))) / (cosDec * cos(latitude)); - double latitudeRadians = Math.toRadians(latitude); - double cosineSunLocalHour = (Math.cos(Math.toRadians(zenith)) - sinSunDeclination * Math.sin(latitudeRadians)) - / (cosineSunDeclination * Math.cos(latitudeRadians)); - - if (cosineSunLocalHour > 1) return Double.NEGATIVE_INFINITY; // the sun never rises on this location (on the specified date) - if (cosineSunLocalHour < -1) return Double.POSITIVE_INFINITY; // the sun never sets on this location (on the specified date) - - // H = (rising ? 360 - acos(cosH) : acos(cosH)) / 15; - double sunLocalHour = Math.toDegrees(Math.acos(cosineSunLocalHour)); - sunLocalHour = (rising ? 360 - sunLocalHour : sunLocalHour) / 15; - - // RA = atan(0.91764 * tan(L)); // RA - //double rightAscension = Math.atan(Math.toRadians(0.91764 * Math.toDegrees( Math.tan(Math.toRadians(sunTrueLong)) ))); - double rightAscension = Math.toDegrees(Math.atan(Math.toRadians(0.91764 * Math.toDegrees( Math.tan(Math.toRadians(sunTrueLong)) )))); - - //--- //RA potentially needs to be adjusted into the range [0,360) by adding/subtracting 360 - //--- if (rightAscension < 0) { rightAscension += 360; } else if (rightAscension > 360) { rightAscension -= 360; } - // RA = (RA + (floor(L/90) - floor(RA/90)) * 90) / 15; - rightAscension = (rightAscension + (Math.floor(sunTrueLong / 90) - Math.floor(rightAscension / 90)) * 90) / 15; - - // T = H + RA - (0.06571 * t) - 6.622 - double localMeanTime = sunLocalHour + rightAscension - (longitudeHour * 0.06571) - 6.622; // T - - // UT = T - lngHour - return localMeanTime - baseLongitudeHour; - } - - private static final int DAYMSEC = 24 * 60 * 60 * 1000; - protected static long convertDate(Calendar calendar, double utcTime) { - // localT = UT + localOffset - int time = (int)(utcTime * 3600000) + calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET); - // UT potentially needs to be adjusted into the range [0,24) by adding/subtracting 24 - //if (utcTime >= 24.) utcTime -= 24; else if (utcTime < 0) utcTime += 24; - if (time >= DAYMSEC) time -= DAYMSEC; else if (time < 0) time += DAYMSEC; - calendar.set(Calendar.HOUR_OF_DAY, 0); - calendar.set(Calendar.MINUTE, 0); - calendar.set(Calendar.SECOND, 0); - calendar.set(Calendar.MILLISECOND, 0); - calendar.add(Calendar.MILLISECOND, time); - return calendar.getTimeInMillis(); - } -} diff --git a/src/test/java/ua/net/uid/utils/time/DailyEquationTest.java b/src/test/java/ua/net/uid/utils/time/DailyEquationTest.java new file mode 100644 index 0000000..95b1de1 --- /dev/null +++ b/src/test/java/ua/net/uid/utils/time/DailyEquationTest.java @@ -0,0 +1,106 @@ +/* + * Copyright 2019 nightfall. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ua.net.uid.utils.time; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.TimeZone; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + +/** + * + * @author nightfall + */ +public class DailyEquationTest { + private static final SimpleDateFormat DATE_FORMAT_DAY = new SimpleDateFormat("yyyyMMdd"); + private static final SimpleDateFormat DATE_FORMAT_MINUTES = new SimpleDateFormat("yyyyMMdd HH:mm"); + + @Test + public void testCalculateEvent() { + //https://edwilliams.org/sunrise_sunset_example.htm + assertEquals(9.441, DailyEquation.calculateEvent(40.9, -74.3 / 15, Zenith.OFFICIAL.getDegrees(), 176, true), 0.001); + } + + @Test + public void testGetSunEvents() throws ParseException { + //https://edwilliams.org/sunrise_sunset_example.htm + assertEvents("America/New_York", "19900625", 40.9, -74.3, "05:26", "20:33"); // June 25, 1990 / Wayne, NJ + + //https://github.com/caarmen/SunriseSunset/blob/master/library/src/test/java/ca/rmen/sunrisesunset/test/SunriseSunsetTest.java + assertEvents("PST", "20130120", 34.0522, -118.2437, "06:56", "17:11"); + assertEvents("CET", "20130120", 48.8567, 2.351, "08:35", "17:28"); + assertEvents("Australia/Sydney", "20121225", -33.86, 151.2111, "05:43", "20:07"); + assertEvents("Japan", "20130501", 35.6938, 139.7036, "04:50", "18:27"); + assertEvents("Europe/Dublin", "20130605", 53.3441, -6.2675, "05:00", "21:46"); + assertEvents("CST", "20130622", 41.8781, -87.6298, "05:15", "20:29"); + assertEvents("Pacific/Honolulu", "20150827", 21.3069, -157.8583, "06:13", "18:51"); + assertEvents("America/Argentina/Buenos_Aires", "20130501", -34.6092, -58.3732, "07:29", "18:11"); + assertEvents("America/Argentina/Buenos_Aires", "20131019", -34.6092, -58.3732, "06:06", "19:10"); + + assertEvents("America/Argentina/Buenos_Aires", "20130126", -34.6092, -58.3732, "06:07", "20:04"); + assertEvents("America/Argentina/Buenos_Aires", "20131020", -34.6092, -58.3732, "06:05", "19:11"); + assertEvents("America/Argentina/Buenos_Aires", "20131031", -34.6092, -58.3732, "05:53", "19:21"); + + assertEvents("Antarctica/McMurdo", "20150419", -77.8456, 166.6693, "10:34", "15:04"); // "10:37", "15:08" + assertEvents("Antarctica/McMurdo", "20150621", -77.8456, 166.6693, Zenith.OFFICIAL, DailyEventType.POLAR_NIGHT, null, null); + assertEvents("Antarctica/McMurdo", "20150921", -77.8456, 166.6693, "06:49", "18:47"); + assertEvents("Antarctica/McMurdo", "20151221", -77.8456, 166.6693, Zenith.OFFICIAL, DailyEventType.POLAR_DAY, null, null); + + //https://github.com/caarmen/SunriseSunset/blob/master/library/src/test/java/ca/rmen/sunrisesunset/test/SunriseSunsetSpecificLocationsTest.java + assertEvents("EST", "20160228", 82.50178, -62.34809, "10:13", "12:47"); // "10:27", "12:19 + assertEvents("EST", "20160228", 82.5018, -62.3481, "10:13", "12:47"); // "10:27", "12:19" + assertEvents("EST", "20160228", 82.50177764892578, -62.34809112548828, "10:13", "12:47"); // "10:17", "12:31" + assertEvents("EST", "20160228", 82.501667, -62.348056, "10:13", "12:47"); // "10:15", "12:32" + assertEvents("EST", "20160228", 82.5, -62.35, "10:13", "12:48"); // "10:14", "12:33" + assertEvents("EST", "20160228", 82.50177764892578, -62.34809112548828, "10:13", "12:47"); // "10:14", "12:33" + + assertEvents("Europe/Kiev", "20190708", 50.401984, 30.531065, "04:55", "21:09" ); + assertEvents("Asia/Kamchatka", "20190706", 53.047252, 158.628714, "05:07", "21:52"); + + assertEvents("America/Moscow", "20181201", 69.000779, 33.116392, "09:14", "09:44"); // Мурманск - https://ru.wikipedia.org/wiki/%D0%9F%D0%BE%D0%BB%D1%8F%D1%80%D0%BD%D0%B0%D1%8F_%D0%BD%D0%BE%D1%87%D1%8C + assertEvents("America/Moscow", "20181202", 69.000779, 33.116392, Zenith.OFFICIAL, DailyEventType.POLAR_NIGHT, null, null); + assertEvents("America/Moscow", "20190111", 69.000779, 33.116392, Zenith.OFFICIAL, DailyEventType.POLAR_NIGHT, null, null); + assertEvents("America/Moscow", "20190112", 69.000779, 33.116392, "09:29", "10:29"); + + assertEvents("Atlantic/Reykjavik", "20190708", 65.67, -18.1, "02:26", "00:06"); // Акюрейри, Регион Нордюрланд-Эйстра, Исландия + + } + + private void assertEvents(String timezone, String date, double lat, double lon, String sr, String ss) throws ParseException { + assertEvents(timezone, date, lat, lon, Zenith.OFFICIAL, DailyEventType.NORMAL_DAY, sr, ss); + } + private void assertEvents(String timezone, String date, double lat, double lon, Zenith zenith, DailyEventType type, String sr, String ss) throws ParseException { + TimeZone tz = TimeZone.getTimeZone(timezone); + + SimpleDateFormat parse = (SimpleDateFormat) DATE_FORMAT_DAY.clone(); + parse.setTimeZone(tz); + + Calendar calendar = Calendar.getInstance(tz); + calendar.setTime(parse.parse(date)); + + DailyEvents events = DailyEquation.getSunEvents(lat, lon, calendar, zenith); + + assertSame(type, events.getType()); + if (type == DailyEventType.NORMAL_DAY) { + SimpleDateFormat format = (SimpleDateFormat) DATE_FORMAT_MINUTES.clone(); + format.setTimeZone(tz); + assertEquals(date + ' ' + sr, format.format(events.getSunrise())); + assertEquals(date + ' ' + ss, format.format(events.getSunset())); + } + } +} diff --git a/src/test/java/ua/net/uid/utils/tools/DailyEquationTest.java b/src/test/java/ua/net/uid/utils/tools/DailyEquationTest.java index 05920f9..3c27827 100644 --- a/src/test/java/ua/net/uid/utils/tools/DailyEquationTest.java +++ b/src/test/java/ua/net/uid/utils/tools/DailyEquationTest.java @@ -1,92 +1 @@ package ua.net.uid.utils.tools; - -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.TimeZone; -import static org.junit.jupiter.api.Assertions.*; -import org.junit.jupiter.api.Test; -import static ua.net.uid.utils.tools.DailyEquation.*; - -/** - * - * @author nightfall - */ -public class DailyEquationTest { - private static final SimpleDateFormat DATE_FORMAT_DAY = new SimpleDateFormat("yyyyMMdd"); - private static final SimpleDateFormat DATE_FORMAT_MINUTES = new SimpleDateFormat("yyyyMMdd HH:mm"); - - @Test - public void testCalculateEvent() { - //https://edwilliams.org/sunrise_sunset_example.htm - assertEquals(9.441, DailyEquation.calculateEvent(40.9, -74.3 / 15, Zenith.OFFICIAL.getDegrees(), 176, true), 0.001); - } - - @Test - public void testGetSunEvents() throws ParseException { - //https://edwilliams.org/sunrise_sunset_example.htm - assertEvents("America/New_York", "19900625", 40.9, -74.3, "05:26", "20:33"); // June 25, 1990 / Wayne, NJ - - //https://github.com/caarmen/SunriseSunset/blob/master/library/src/test/java/ca/rmen/sunrisesunset/test/SunriseSunsetTest.java - assertEvents("PST", "20130120", 34.0522, -118.2437, "06:56", "17:11"); - assertEvents("CET", "20130120", 48.8567, 2.351, "08:35", "17:28"); - assertEvents("Australia/Sydney", "20121225", -33.86, 151.2111, "05:43", "20:07"); - assertEvents("Japan", "20130501", 35.6938, 139.7036, "04:50", "18:27"); - assertEvents("Europe/Dublin", "20130605", 53.3441, -6.2675, "05:00", "21:46"); - assertEvents("CST", "20130622", 41.8781, -87.6298, "05:15", "20:29"); - assertEvents("Pacific/Honolulu", "20150827", 21.3069, -157.8583, "06:13", "18:51"); - assertEvents("America/Argentina/Buenos_Aires", "20130501", -34.6092, -58.3732, "07:29", "18:11"); - assertEvents("America/Argentina/Buenos_Aires", "20131019", -34.6092, -58.3732, "06:06", "19:10"); - - assertEvents("America/Argentina/Buenos_Aires", "20130126", -34.6092, -58.3732, "06:07", "20:04"); - assertEvents("America/Argentina/Buenos_Aires", "20131020", -34.6092, -58.3732, "06:05", "19:11"); - assertEvents("America/Argentina/Buenos_Aires", "20131031", -34.6092, -58.3732, "05:53", "19:21"); - - assertEvents("Antarctica/McMurdo", "20150419", -77.8456, 166.6693, "10:34", "15:04"); // "10:37", "15:08" - assertEvents("Antarctica/McMurdo", "20150621", -77.8456, 166.6693, Zenith.OFFICIAL, Type.POLAR_NIGHT, null, null); - assertEvents("Antarctica/McMurdo", "20150921", -77.8456, 166.6693, "06:49", "18:47"); - assertEvents("Antarctica/McMurdo", "20151221", -77.8456, 166.6693, Zenith.OFFICIAL, Type.POLAR_DAY, null, null); - - //https://github.com/caarmen/SunriseSunset/blob/master/library/src/test/java/ca/rmen/sunrisesunset/test/SunriseSunsetSpecificLocationsTest.java - assertEvents("EST", "20160228", 82.50178, -62.34809, "10:13", "12:47"); // "10:27", "12:19 - assertEvents("EST", "20160228", 82.5018, -62.3481, "10:13", "12:47"); // "10:27", "12:19" - assertEvents("EST", "20160228", 82.50177764892578, -62.34809112548828, "10:13", "12:47"); // "10:17", "12:31" - assertEvents("EST", "20160228", 82.501667, -62.348056, "10:13", "12:47"); // "10:15", "12:32" - assertEvents("EST", "20160228", 82.5, -62.35, "10:13", "12:48"); // "10:14", "12:33" - assertEvents("EST", "20160228", 82.50177764892578, -62.34809112548828, "10:13", "12:47"); // "10:14", "12:33" - - assertEvents("Europe/Kiev", "20190708", 50.401984, 30.531065, "04:55", "21:09" ); - assertEvents("Asia/Kamchatka", "20190706", 53.047252, 158.628714, "05:07", "21:52"); - - assertEvents("America/Moscow", "20181201", 69.000779, 33.116392, "09:14", "09:44"); // Мурманск - https://ru.wikipedia.org/wiki/%D0%9F%D0%BE%D0%BB%D1%8F%D1%80%D0%BD%D0%B0%D1%8F_%D0%BD%D0%BE%D1%87%D1%8C - assertEvents("America/Moscow", "20181202", 69.000779, 33.116392, Zenith.OFFICIAL, Type.POLAR_NIGHT, null, null); - assertEvents("America/Moscow", "20190111", 69.000779, 33.116392, Zenith.OFFICIAL, Type.POLAR_NIGHT, null, null); - assertEvents("America/Moscow", "20190112", 69.000779, 33.116392, "09:29", "10:29"); - - assertEvents("Atlantic/Reykjavik", "20190708", 65.67, -18.1, "02:26", "00:06"); // Акюрейри, Регион Нордюрланд-Эйстра, Исландия - - } - - private void assertEvents(String timezone, String date, double lat, double lon, String sr, String ss) throws ParseException { - assertEvents(timezone, date, lat, lon, Zenith.OFFICIAL, Type.NORMAL_DAY, sr, ss); - } - private void assertEvents(String timezone, String date, double lat, double lon, Zenith zenith, Type type, String sr, String ss) throws ParseException { - TimeZone tz = TimeZone.getTimeZone(timezone); - - SimpleDateFormat parse = (SimpleDateFormat) DATE_FORMAT_DAY.clone(); - parse.setTimeZone(tz); - - Calendar calendar = Calendar.getInstance(tz); - calendar.setTime(parse.parse(date)); - - Events events = DailyEquation.getSunEvents(lat, lon, calendar, zenith); - - assertSame(type, events.getType()); - if (type == Type.NORMAL_DAY) { - SimpleDateFormat format = (SimpleDateFormat) DATE_FORMAT_MINUTES.clone(); - format.setTimeZone(tz); - assertEquals(date + ' ' + sr, format.format(events.getSunrise())); - assertEquals(date + ' ' + ss, format.format(events.getSunset())); - } - } -}