From 5dd0df5bbf2799e690cf651a9ea9415d0c0d16ab Mon Sep 17 00:00:00 2001 From: KosherJava Date: Wed, 1 Jan 2025 12:55:16 -0500 Subject: [PATCH] AstronomicalCalendar - solar midnight changes - Fix incorrect documentation on getTemporalHour() and getTemporalHour(Date startOfDay, Date endOfDay) - Solar midnight is now the last zman of the day, not the first - If calculated for Feb 8, it will be the midnight boundary between Jan 8 and Jan 9. - Deprecate getSunLowerTransit() - use getSolarMidnight() instead (this is already done internally) - Changes to getSolarMidnight() to use the calculator implementations - Update JavaDocs to avoid warnings on recent JDKs and other tweaks --- .../zmanim/AstronomicalCalendar.java | 92 +++++++++++-------- 1 file changed, 53 insertions(+), 39 deletions(-) diff --git a/src/main/java/com/kosherjava/zmanim/AstronomicalCalendar.java b/src/main/java/com/kosherjava/zmanim/AstronomicalCalendar.java index fd2bd181..79505606 100644 --- a/src/main/java/com/kosherjava/zmanim/AstronomicalCalendar.java +++ b/src/main/java/com/kosherjava/zmanim/AstronomicalCalendar.java @@ -1,6 +1,6 @@ /* * Zmanim Java API - * Copyright (C) 2004-2024 Eliyahu Hershfeld + * Copyright (C) 2004-2025 Eliyahu Hershfeld * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General * Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) @@ -63,7 +63,7 @@ * Date sunrise = ac.getSunrise(); * * - * @author © Eliyahu Hershfeld 2004 - 2024 + * @author © Eliyahu Hershfeld 2004 - 2025 */ public class AstronomicalCalendar implements Cloneable { @@ -229,7 +229,8 @@ public Date getSunset() { * such as in the Arctic Circle where there is at least one day a year where the sun does not rise, and one * where it does not set, a null will be returned. See detailed explanation on top of the page. * @see AstronomicalCalendar#getSunset - * @see AstronomicalCalendar#getUTCSeaLevelSunset 2see {@link #getSunset()} + * @see AstronomicalCalendar#getUTCSeaLevelSunset + * @see #getSunset() */ public Date getSeaLevelSunset() { double sunset = getUTCSeaLevelSunset(GEOMETRIC_ZENITH); @@ -447,12 +448,12 @@ public double getUTCSeaLevelSunset(double zenith) { } /** - * A method that returns an {@link AstronomicalCalculator#getElevationAdjustment(double) elevation adjusted} - * temporal (solar) hour. The day from {@link #getSunrise() sunrise} to {@link #getSunset() sunset} is split into 12 - * equal parts with each one being a temporal hour. + * A method that returns a sea-level based temporal (solar) hour. The day from {@link #getSeaLevelSunrise() + * sea-level sunrise} to {@link #getSeaLevelSunset() sea-level sunset} is split into 12 equal parts with each + * one being a temporal hour. * - * @see #getSunrise() - * @see #getSunset() + * @see #getSeaLevelSunrise() + * @see #getSeaLevelSunset() * @see #getTemporalHour(Date, Date) * * @return the long millisecond length of a temporal hour. If the calculation can't be computed, @@ -467,8 +468,8 @@ public long getTemporalHour() { /** * A utility method that will allow the calculation of a temporal (solar) hour based on the sunrise and sunset * passed as parameters to this method. An example of the use of this method would be the calculation of a - * non-elevation adjusted temporal hour by passing in {@link #getSeaLevelSunrise() sea level sunrise} and - * {@link #getSeaLevelSunset() sea level sunset} as parameters. + * elevation adjusted temporal hour by passing in {@link #getSunrise() sunrise} and + * {@link #getSunset() sunset} as parameters. * * @param startOfDay * The start of the day. @@ -523,51 +524,58 @@ public Date getSunTransit() { * set} to use the {@link com.kosherjava.zmanim.util.NOAACalculator} (the default) it will calculate astronomical * midnight. If the calendar instance is to use the {@link com.kosherjava.zmanim.util.SunTimesCalculator}, that does not * have code to calculate astronomical noon, midnight is calculated as halfway between sea level sunrise and sea level - * sunset on the other side of the world (180° awa)y, which can be slightly off the real transit time due to changes + * sunset on the other side of the world (180° away), which can be slightly off the real transit time due to changes * in declination (the lengthening or shortening day). See The Definition of Chatzos for details on the proper * definition of solar noon / midday. * - * @return the Date representing Sun's lower transit. If the calculation can't be computed such as when using - * the {@link com.kosherjava.zmanim.util.SunTimesCalculator USNO calculator} that does not support getting solar - * midnight for the Arctic Circle (where there is at least one day a year where the sun does not rise, and one - * where it does not set), a null will be returned. See detailed explanation on top of the page. + * @deprecated This method was replaced by {@link #getSolarMidnight()} and will be removed in v3.0. + * + * @return the Date representing Sun's lower transit at the end of the current day. If the calculation can't + * be computed such as when using the {@link com.kosherjava.zmanim.util.SunTimesCalculator USNO calculator} that + * does not support getting solar noon or midnight for the Arctic Circle (where there is at least one day a year + * where the sun does not rise, and one where it does not set), a null will be returned. This is not + * relevant when using the {@link com.kosherjava.zmanim.util.NOAACalculator NOAA Calculator} that is never expected + * to return null. See the detailed explanation on top of the page. * * @see #getSunTransit() + * @see #getSolarMidnight() * @see com.kosherjava.zmanim.util.NOAACalculator#getUTCNoon(Calendar, GeoLocation) * @see com.kosherjava.zmanim.util.SunTimesCalculator#getUTCNoon(Calendar, GeoLocation) */ + @Deprecated // (since="2.6", forRemoval=true)// add back once Java 9 is the minimum supported version public Date getSunLowerTransit() { - Calendar cal = getAdjustedCalendar(); - GeoLocation lowerGeoLocation = (GeoLocation) getGeoLocation().clone(); - double meridian = lowerGeoLocation.getLongitude(); - double lowerMeridian = meridian + 180; - if (lowerMeridian > 180){ - lowerMeridian = lowerMeridian - 360; - cal.add(Calendar.DAY_OF_MONTH, -1); - } - lowerGeoLocation.setLongitude(lowerMeridian); - double noon = getAstronomicalCalculator().getUTCNoon(cal, lowerGeoLocation); - return getDateFromTime(noon, SolarEvent.MIDNIGHT); + return getSolarMidnight(); } /** - * A method that returns "solar" midnight, or the time when the sun is at its nadir. The current calculation is halfway between today and - * tomorrow's {@link #getSunTransit() sun transit}. + * A method that returns solar midnight at the end of the current day (that may actually be after midnight of the day it + * is being calculated for). It occurs when the Sun is transiting the lower celestial meridian, or + * when the sun is at it's nadir. The calculations used by this class + * depend on the {@link AstronomicalCalculator} used. If this calendar instance is {@link + * #setAstronomicalCalculator(AstronomicalCalculator) set} to use the {@link com.kosherjava.zmanim.util.NOAACalculator} + * (the default) it will calculate astronomical midnight. If the calendar instance is to use the {@link + * com.kosherjava.zmanim.util.SunTimesCalculator USNO Calculator}, that does not have code to calculate astronomical noon, + * midnight is calculated as 12 hours after halfway between sea level sunrise and sea level sunset of that day. This can + * be slightly off the real transit time due to changes in declination (the lengthening or shortening day). See The Definition of Chatzos for details on the proper + * definition of solar noon / midday. + * + * @return the Date representing Sun's lower transit at the end of the current day. If the calculation can't + * be computed such as when using the {@link com.kosherjava.zmanim.util.SunTimesCalculator USNO calculator} that + * does not support getting solar noon or midnight for the Arctic Circle (where there is at least one day a year + * where the sun does not rise, and one where it does not set), a null will be returned. This is not + * relevant when using the {@link com.kosherjava.zmanim.util.NOAACalculator NOAA Calculator} that is never expected + * to return null. See the detailed explanation on top of the page. * - * @return the Date of astronomical solar midnight. If the calculation can't be computed such as - * when using the {@link com.kosherjava.zmanim.util.SunTimesCalculator USNO calculator} that does not - * support getting solar noon for the Arctic Circle (where there is at least one day a year where the - * sun does not rise, and one where it does not set), a null will be returned. See - * detailed explanation on top of the page. + * @see #getSunTransit() * @see com.kosherjava.zmanim.util.NOAACalculator#getUTCNoon(Calendar, GeoLocation) * @see com.kosherjava.zmanim.util.SunTimesCalculator#getUTCNoon(Calendar, GeoLocation) */ public Date getSolarMidnight() { - AstronomicalCalendar clonedCal = (AstronomicalCalendar) clone(); - clonedCal.getCalendar().add(Calendar.DATE, 1); - return getTimeOffset(getSunTransit(), (clonedCal.getSunTransit().getTime() - getSunTransit().getTime()) / 2); + double noon = getAstronomicalCalculator().getUTCMidnight(getAdjustedCalendar(), getGeoLocation()); + return getDateFromTime(noon, SolarEvent.MIDNIGHT); } /** @@ -600,6 +608,7 @@ protected enum SolarEvent { /**SUNRISE A solar event related to sunrise*/SUNRISE, /**SUNSET A solar event related to sunset*/SUNSET, /**NOON A solar event related to noon*/NOON, /**MIDNIGHT A solar event related to midnight*/MIDNIGHT } + /** * A method that returns a Date from the time passed in as a parameter. * @@ -636,8 +645,8 @@ protected Date getDateFromTime(double time, SolarEvent solarEvent) { cal.add(Calendar.DAY_OF_MONTH, -1); } else if (solarEvent == SolarEvent.SUNSET && localTimeHours + hours < 6) { cal.add(Calendar.DAY_OF_MONTH, 1); - } else if (solarEvent == SolarEvent.MIDNIGHT && localTimeHours + hours > 12) { - cal.add(Calendar.DAY_OF_MONTH, -1); + } else if (solarEvent == SolarEvent.MIDNIGHT && localTimeHours + hours < 12) { + cal.add(Calendar.DAY_OF_MONTH, 1); } cal.set(Calendar.HOUR_OF_DAY, hours); @@ -747,6 +756,8 @@ private Calendar getAdjustedCalendar(){ } /** + * Returns an XML formatted representation of the class using the default output of the + * {@link com.kosherjava.zmanim.util.ZmanimFormatter#toXML(AstronomicalCalendar) toXML} method. * @return an XML formatted representation of the class. It returns the default output of the * {@link com.kosherjava.zmanim.util.ZmanimFormatter#toXML(AstronomicalCalendar) toXML} method. * @see com.kosherjava.zmanim.util.ZmanimFormatter#toXML(AstronomicalCalendar) @@ -757,6 +768,8 @@ public String toString() { } /** + * Returns a JSON formatted representation of the class using the default output of the + * {@link com.kosherjava.zmanim.util.ZmanimFormatter#toJSON(AstronomicalCalendar) toJSON} method. * @return a JSON formatted representation of the class. It returns the default output of the * {@link com.kosherjava.zmanim.util.ZmanimFormatter#toJSON(AstronomicalCalendar) toJSON} method. * @see com.kosherjava.zmanim.util.ZmanimFormatter#toJSON(AstronomicalCalendar) @@ -851,6 +864,7 @@ public Calendar getCalendar() { } /** + * Sets the Calendar object for us in this class. * @param calendar * The calendar to set. */