001/*
002 * Zmanim Java API
003 * Copyright (C) 2004-2023 Eliyahu Hershfeld
004 *
005 * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General
006 * Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option)
007 * any later version.
008 *
009 * This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied
010 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
011 * details.
012 * You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to
013 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA,
014 * or connect to: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
015 */
016package com.kosherjava.zmanim;
017
018import java.util.Calendar;
019import java.util.Date;
020
021import com.kosherjava.zmanim.hebrewcalendar.JewishCalendar;
022import com.kosherjava.zmanim.util.AstronomicalCalculator;
023import com.kosherjava.zmanim.util.GeoLocation;
024
025/**
026 * The ZmanimCalendar is a specialized calendar that can calculate sunrise, sunset and Jewish <em>zmanim</em>
027 * (religious times) for prayers and other Jewish religious duties. This class contains the main functionality of the
028 * <em>Zmanim</em> library. For a much more extensive list of <em>zmanim</em>, use the {@link ComplexZmanimCalendar} that
029 * extends this class. See documentation for the {@link ComplexZmanimCalendar} and {@link AstronomicalCalendar} for
030 * simple examples on using the API. 
031 * <strong>Elevation based <em>zmanim</em> (even sunrise and sunset) should not be used <em>lekula</em> without the guidance
032 * of a <em>posek</em></strong>. According to Rabbi Dovid Yehudah Bursztyn in his
033 * <a href="https://www.worldcat.org/oclc/1158574217">Zmanim Kehilchasam, 7th edition</a> chapter 2, section 7 (pages 181-182)
034 * and section 9 (pages 186-187), no <em>zmanim</em> besides sunrise and sunset should use elevation. However, Rabbi Yechiel
035 * Avrahom Zilber in the <a href="https://hebrewbooks.org/51654">Birur Halacha Vol. 6</a> Ch. 58 Pages
036 * <a href="https://hebrewbooks.org/pdfpager.aspx?req=51654&amp;pgnum=42">34</a> and
037 * <a href="https://hebrewbooks.org/pdfpager.aspx?req=51654&amp;pgnum=50">42</a> is of the opinion that elevation should be
038 * accounted for in <em>zmanim</em> calculations. Related to this, Rabbi Yaakov Karp in <a href=
039 * "https://www.worldcat.org/oclc/919472094">Shimush Zekeinim</a>, Ch. 1, page 17 states that obstructing horizons should
040 * be factored into <em>zmanim</em> calculations. The setting defaults to false (elevation will not be used for
041 * <em>zmanim</em> calculations besides sunrise and sunset), unless the setting is changed to true in {@link
042 * #setUseElevation(boolean)}. This will impact sunrise and sunset-based <em>zmanim</em> such as {@link #getSunrise()},
043 * {@link #getSunset()}, {@link #getSofZmanShmaGRA()}, <em>alos</em>-based <em>zmanim</em> such as {@link #getSofZmanShmaMGA()}
044 * that are based on a fixed offset of sunrise or sunset and <em>zmanim</em> based on a percentage of the day such as
045 * {@link ComplexZmanimCalendar#getSofZmanShmaMGA90MinutesZmanis()} that are based on sunrise and sunset. Even when set to
046 * true it will not impact <em>zmanim</em> that are a degree-based offset of sunrise and sunset, such as {@link
047 * ComplexZmanimCalendar#getSofZmanShmaMGA16Point1Degrees()} or {@link ComplexZmanimCalendar#getSofZmanShmaBaalHatanya()} since
048 * these <em>zmanim</em> are not linked to sunrise or sunset times (the calculations are based on the astronomical definition of
049 * sunrise and sunset calculated in a vacuum with the solar radius above the horizon), and are therefore not impacted by the use
050 * of elevation.
051 * For additional information on the <em>halachic</em> impact of elevation on <em>zmanim</em> see:
052 * <ul>
053 * <li><a href="https://www.nli.org.il/en/books/NNL_ALEPH002542826/NLI">Zmanei Halacha Lema'aseh</a> 4th edition by <a href=
054 * "http://beinenu.com/rabbis/%D7%94%D7%A8%D7%91-%D7%99%D7%93%D7%99%D7%93%D7%99%D7%94-%D7%9E%D7%A0%D7%AA">Rabbi Yedidya Manat</a>.
055 * See section 1, pages 11-12 for a very concise write-up, with details in section 2, pages 37 - 63 and 133 - 151.</li>
056 * <li><a href="https://www.worldcat.org/oclc/1158574217">Zmanim Kehilchasam</a> 7th edition, by Rabbi Dovid Yehuda Burstein,  vol 1,
057 * chapter 2, pages 95 - 188.</li>
058 * <li><a href="https://www.worldcat.org/oclc/36089452">Hazmanim Bahalacha</a> by Rabbi Chaim Banish , perek 7, pages 53 - 63.</li>
059 * </ul>
060 * 
061 * <p><b>Note:</b> It is important to read the technical notes on top of the {@link AstronomicalCalculator} documentation
062 * before using this code.
063 * <p>I would like to thank <a href="https://www.worldcat.org/search?q=au%3AShakow%2C+Yaakov">Rabbi Yaakov Shakow</a>, the
064 * author of Luach Ikvei Hayom who spent a considerable amount of time reviewing, correcting and making suggestions on the
065 * documentation in this library.
066 * <h2>Disclaimer:</h2> I did my best to get accurate results, but please double-check before relying on these
067 * <em>zmanim</em> for <em>halacha lema'aseh</em>.
068 * 
069 * @author &copy; Eliyahu Hershfeld 2004 - 2023
070 */
071public class ZmanimCalendar extends AstronomicalCalendar {
072        
073        /**
074         * Is elevation factored in for some <em>zmanim</em> (see {@link #isUseElevation()} for additional information).
075         * @see #isUseElevation()
076         * @see #setUseElevation(boolean)
077         */
078        private boolean useElevation;
079
080        /**
081         * Is elevation above sea level calculated for times besides sunrise and sunset. According to Rabbi Dovid Yehuda
082         * Bursztyn in his <a href="https://www.worldcat.org/oclc/659793988">Zmanim Kehilchasam (second edition published
083         * in 2007)</a> chapter 2 (pages 186-187) no <em>zmanim</em> besides sunrise and sunset should use elevation. However
084         * Rabbi Yechiel Avrahom Zilber in the <a href="https://hebrewbooks.org/51654">Birur Halacha Vol. 6</a> Ch. 58 Pages
085         * <a href="https://hebrewbooks.org/pdfpager.aspx?req=51654&amp;pgnum=42">34</a> and <a href=
086         * "https://hebrewbooks.org/pdfpager.aspx?req=51654&amp;pgnum=50">42</a> is of the opinion that elevation should be
087         * accounted for in <em>zmanim</em> calculations. Related to this, Rabbi Yaakov Karp in <a href=
088         * "https://www.worldcat.org/oclc/919472094">Shimush Zekeinim</a>, Ch. 1, page 17 states that obstructing horizons
089         * should be factored into <em>zmanim</em> calculations.The setting defaults to false (elevation will not be used for
090         * <em>zmanim</em> calculations), unless the setting is changed to true in {@link #setUseElevation(boolean)}. This will
091         * impact sunrise and sunset based <em>zmanim</em> such as {@link #getSunrise()}, {@link #getSunset()},
092         * {@link #getSofZmanShmaGRA()}, alos based <em>zmanim</em> such as {@link #getSofZmanShmaMGA()} that are based on a
093         * fixed offset of sunrise or sunset and <em>zmanim</em> based on a percentage of the day such as {@link
094         * ComplexZmanimCalendar#getSofZmanShmaMGA90MinutesZmanis()} that are based on sunrise and sunset. It will not impact
095         * <em>zmanim</em> that are a degree based offset of sunrise and sunset, such as
096         * {@link ComplexZmanimCalendar#getSofZmanShmaMGA16Point1Degrees()} or {@link ComplexZmanimCalendar#getSofZmanShmaBaalHatanya()}.
097         * 
098         * @return if the use of elevation is active
099         * 
100         * @see #setUseElevation(boolean)
101         */
102        public boolean isUseElevation() {
103                return useElevation;
104        }
105
106        /**
107         * Sets whether elevation above sea level is factored into <em>zmanim</em> calculations for times besides sunrise and sunset.
108         * See {@link #isUseElevation()} for more details. 
109         * @see #isUseElevation()
110         * 
111         * @param useElevation set to true to use elevation in <em>zmanim</em> calculations
112         */
113        public void setUseElevation(boolean useElevation) {
114                this.useElevation = useElevation;
115        }
116        
117        /**
118         * Is astronomical <em>chatzos</em> used for <em>zmanim</em> calculations. The default value of <code>true</code> will
119         * keep the standard astronomical <em>chatzos</em> calculation, while setting it to <code>false</code> will use half of
120         * a solar day calculation for <em>chatzos</em>.
121         * @see #isUseAstronomicalChatzos()
122         * @see #setUseAstronomicalChatzos(boolean)
123         * @see #getChatzos()
124         * @see #getSunTransit()
125         * @see #getChatzosAsHalfDay()
126         * @see #useAstronomicalChatzosForOtherZmanim
127         */
128        private boolean useAstronomicalChatzos = true;
129        
130        /**
131         * Is {@link #getSunTransit() astronomical <em>chatzos</em>} used for {@link #getChatzos()} for enhanced accuracy. For
132         * example as the day is lengthens, the second half of the day is longer than the first and astronomical <em>chatzos</em>
133         * would be a drop earlier than half of the time between sunrise and sunset.
134         * 
135         * @todo In the future, if this is set to true, the following may change to enhance accuracy. {@link #getSofZmanShmaGRA()
136         * <em>Sof zman Shma</em> GRA} would be calculated as 3 <em>shaaos zmaniyos</em> after sunrise, but the <em>shaaos
137         * zmaniyos</em> would be calculated a a 6th of the time between sunrise and <em>chatzos</em>, as opposed to a 12th of the
138         * time between sunrise and sunset. {@link #getMinchaGedola() <em>mincha gedola</em>} will be calculated as half a
139         * <em>shaah zmanis</em> of afternoon hours (a 6th of the time between <em>chatzos</em> and sunset after astronomical
140         * <em>chatzos</em> as opposed to 6.5 <em>shaaos zmaniyos</em> after sunrise. {@link #getPlagHamincha() <em>Plag
141         * hamincha</em>} would be calculated as 4.75 <em>shaaos zmaniyos</em> after astronomical <em>chatzos</em> as opposed to 10.75
142         * <em>shaaos zmaniyos</em> after sunrise. Etc.
143         * 
144         * @return if the use of astronomical <em>chatzos</em> is active.
145         * @see #useAstronomicalChatzos
146         * @see #setUseAstronomicalChatzos(boolean)
147         * @see #getChatzos()
148         * @see #getSunTransit()
149         * @see #getChatzosAsHalfDay()
150         * @see #isUseAstronomicalChatzosForOtherZmanim()
151         */
152        public boolean isUseAstronomicalChatzos() {
153                return useAstronomicalChatzos;
154        }
155
156        /**
157         * Sets if astronomical <em>chatzos</em> should be used in calculations of other <em>zmanim</em> for enhanced accuracy.
158         * @param useAstronomicalChatzos set to true to use astronomical in <em>chatzos</em> in <em>zmanim</em> calculations.
159         * @see #useAstronomicalChatzos
160         * @see #isUseAstronomicalChatzos()
161         * @see #getChatzos()
162         * @see #getSunTransit()
163         * @see #getChatzosAsHalfDay()
164         * @see #setUseAstronomicalChatzosForOtherZmanim(boolean)
165         */
166        public void setUseAstronomicalChatzos(boolean useAstronomicalChatzos) {
167                this.useAstronomicalChatzos = useAstronomicalChatzos;
168        }
169        
170        /**
171         * Is astronomical <em>chatzos</em> used for <em>zmanim</em> calculations besides <em>chatzos</em> itself for enhanced
172         * accuracy. The default value of <code>false</code> will keep the standard start to end of day calculations, while setting
173         * it to <code>true</code> will use half of a solar day calculation for <em>zmanim</em>.
174         * @see #isUseAstronomicalChatzosForOtherZmanim()
175         * @see #setUseAstronomicalChatzosForOtherZmanim(boolean)
176         * @see #isUseAstronomicalChatzos()
177         * @see #setUseAstronomicalChatzos(boolean)
178         * @see #getChatzos()
179         */
180        private boolean useAstronomicalChatzosForOtherZmanim = false;
181        
182        /**
183         * Is astronomical <em>chatzos</em> used for <em>zmanim</em> calculations besides <em>chatzos</em> itself for enhanced
184         * accuracy. For example as the day is lengthening (as we approach spring season), the second half of the day is longer than
185         * the first and astronomical <em>chatzos</em> would be a drop earlier than half of the time between sunrise and sunset.
186         * Conversely, the second half of the day would be shorter in the fall season as the days start getting shorter.
187         * 
188         * @todo In the future, if this is set to true, the following may change to enhance accuracy. {@link #getSofZmanShmaGRA()
189         * <em>Sof zman Shma</em> GRA} would be calculated as 3 <em>shaaos zmaniyos</em> after sunrise, but the <em>shaaos
190         * zmaniyos</em> would be calculated a a 6th of the time between sunrise and <em>chatzos</em>, as opposed to a 12th of the
191         * time between sunrise and sunset. {@link #getMinchaGedola() <em>mincha gedola</em>} will be calculated as half a
192         * <em>shaah zmanis</em> of afternoon hours (a 6th of the time between <em>chatzos</em> and sunset after astronomical
193         * <em>chatzos</em> as opposed to 6.5 <em>shaaos zmaniyos</em> after sunrise. {@link #getPlagHamincha() <em>Plag
194         * hamincha</em>} would be calculated as 4.75 <em>shaaos zmaniyos</em> after astronomical <em>chatzos</em> as opposed to 10.75
195         * <em>shaaos zmaniyos</em> after sunrise. Etc.
196         * 
197         * @return if the use of astronomical <em>chatzos</em> is active.
198         * @see #useAstronomicalChatzosForOtherZmanim
199         * @see #setUseAstronomicalChatzosForOtherZmanim(boolean)
200         * @see #useAstronomicalChatzos
201         * @see #setUseAstronomicalChatzos(boolean)
202         */
203        public boolean isUseAstronomicalChatzosForOtherZmanim() {
204                return useAstronomicalChatzosForOtherZmanim;
205        }
206
207        /**
208         * Sets if astronomical <em>chatzos</em> should be used in calculations of other <em>zmanim</em> for enhanced accuracy.
209         * @param useAstronomicalChatzosForOtherZmanim set to true to use astronomical in <em>chatzos</em> in <em>zmanim</em> calculations.
210         * @see #useAstronomicalChatzos
211         * @see #isUseAstronomicalChatzos()
212         */
213        public void setUseAstronomicalChatzosForOtherZmanim(boolean useAstronomicalChatzosForOtherZmanim) {
214                this.useAstronomicalChatzosForOtherZmanim = useAstronomicalChatzosForOtherZmanim;
215        }
216
217        /**
218         * The zenith of 16.1&deg; below geometric zenith (90&deg;). This calculation is used for determining <em>alos</em>
219         * (dawn) and <em>tzais</em> (nightfall) in some opinions. It is based on the calculation that the time between dawn
220         * and sunrise (and sunset to nightfall) is 72 minutes, the time that is takes to walk 4 <em>mil</em> at 18 minutes
221         * a mil (<em><a href="https://en.wikipedia.org/wiki/Maimonides">Rambam</a></em> and others). The sun's position at
222         * 72 minutes before {@link #getSunrise sunrise} in Jerusalem <a href=
223         * "https://kosherjava.com/2022/01/12/equinox-vs-equilux-zmanim-calculations/">around the equinox / equilux</a> is
224         * 16.1&deg; below {@link #GEOMETRIC_ZENITH geometric zenith}.
225         * 
226         * @see #getAlosHashachar()
227         * @see ComplexZmanimCalendar#getAlos16Point1Degrees()
228         * @see ComplexZmanimCalendar#getTzais16Point1Degrees()
229         * @see ComplexZmanimCalendar#getSofZmanShmaMGA16Point1Degrees()
230         * @see ComplexZmanimCalendar#getSofZmanTfilaMGA16Point1Degrees()
231         * @see ComplexZmanimCalendar#getMinchaGedola16Point1Degrees()
232         * @see ComplexZmanimCalendar#getMinchaKetana16Point1Degrees()
233         * @see ComplexZmanimCalendar#getPlagHamincha16Point1Degrees()
234         * @see ComplexZmanimCalendar#getPlagAlos16Point1ToTzaisGeonim7Point083Degrees()
235         * @see ComplexZmanimCalendar#getSofZmanShmaAlos16Point1ToSunset()
236         */
237        protected static final double ZENITH_16_POINT_1 = GEOMETRIC_ZENITH + 16.1;
238
239        /**
240         * The zenith of 8.5&deg; below geometric zenith (90&deg;). This calculation is used for calculating <em>alos</em>
241         * (dawn) and <em>tzais</em> (nightfall) in some opinions. This calculation is based on the position of the sun 36
242         * minutes after {@link #getSunset sunset} in Jerusalem <a href=
243         * "https://kosherjava.com/2022/01/12/equinox-vs-equilux-zmanim-calculations/">around the equinox / equilux</a>, which
244         * is 8.5&deg; below {@link #GEOMETRIC_ZENITH geometric zenith}. The <em><a href=
245         * "https://www.worldcat.org/oclc/29283612">Ohr Meir</a></em> considers this the time that 3 small stars are visible,
246         * which is later than the required 3 medium stars.
247         * 
248         * @see #getTzais()
249         * @see ComplexZmanimCalendar#getTzaisGeonim8Point5Degrees()
250         */
251        protected static final double ZENITH_8_POINT_5 = GEOMETRIC_ZENITH + 8.5;
252
253        /**
254         * The default <em>Shabbos</em> candle lighting offset is 18 minutes. This can be changed via the
255         * {@link #setCandleLightingOffset(double)} and retrieved by the {@link #getCandleLightingOffset()}.
256         */
257        private double candleLightingOffset = 18;
258        
259        /**
260         * This method will return {@link #getSeaLevelSunrise() sea level sunrise} if {@link #isUseElevation()} is false (the
261         * default), or elevation adjusted {@link AstronomicalCalendar#getSunrise()} if it is true. This allows relevant <em>zmanim</em>
262         * in this and extending classes (such as the {@link ComplexZmanimCalendar}) to automatically adjust to the elevation setting.
263         * 
264         * @return {@link #getSeaLevelSunrise()} if {@link #isUseElevation()} is false (the default), or elevation adjusted
265         *         {@link AstronomicalCalendar#getSunrise()} if it is true.
266         * @see com.kosherjava.zmanim.AstronomicalCalendar#getSunrise()
267         */
268        protected Date getElevationAdjustedSunrise() {
269                if(isUseElevation()) {
270                        return super.getSunrise();
271                }
272                return getSeaLevelSunrise();
273        }
274        
275        /**
276         * This method will return {@link #getSeaLevelSunrise() sea level sunrise} if {@link #isUseElevation()} is false (the default),
277         * or elevation adjusted {@link AstronomicalCalendar#getSunrise()} if it is true. This allows relevant <em>zmanim</em>
278         * in this and extending classes (such as the {@link ComplexZmanimCalendar}) to automatically adjust to the elevation setting.
279         * 
280         * @return {@link #getSeaLevelSunset()} if {@link #isUseElevation()} is false (the default), or elevation adjusted
281         *         {@link AstronomicalCalendar#getSunset()} if it is true.
282         * @see com.kosherjava.zmanim.AstronomicalCalendar#getSunset()
283         */
284        protected Date getElevationAdjustedSunset() {
285                if(isUseElevation()) {
286                        return super.getSunset();
287                }
288                return getSeaLevelSunset();
289        }
290
291        /**
292         * A method that returns <em>tzais</em> (nightfall) when the sun is {@link #ZENITH_8_POINT_5 8.5&deg;} below the
293         * {@link #GEOMETRIC_ZENITH geometric horizon} (90&deg;) after {@link #getSunset sunset}, a time that Rabbi Meir
294         * Posen in his the <em><a href="https://www.worldcat.org/oclc/29283612">Ohr Meir</a></em> calculated that 3 small
295         * stars are visible, which is later than the required 3 medium stars. See the {@link #ZENITH_8_POINT_5} constant.
296         * 
297         * @see #ZENITH_8_POINT_5
298         * 
299         * @return The <code>Date</code> of nightfall. If the calculation can't be computed such as northern and southern
300         *         locations even south of the Arctic Circle and north of the Antarctic Circle where the sun may not reach
301         *         low enough below the horizon for this calculation, a <code>null</code> will be returned. See detailed
302         *         explanation on top of the {@link AstronomicalCalendar} documentation.
303         * @see #ZENITH_8_POINT_5
304         * ComplexZmanimCalendar#getTzaisGeonim8Point5Degrees() that returns an identical time to this generic <em>tzais</em>
305         */
306        public Date getTzais() {
307                return getSunsetOffsetByDegrees(ZENITH_8_POINT_5);
308        }
309
310        /**
311         * Returns <em>alos</em> (dawn) based on the time when the sun is {@link #ZENITH_16_POINT_1 16.1&deg;} below the
312         * eastern {@link #GEOMETRIC_ZENITH geometric horizon} before {@link #getSunrise sunrise}. This is based on the
313         * calculation that the time between dawn and sunrise (and sunset to nightfall) is 72 minutes, the time that is
314         * takes to walk 4 <em>mil</em> at 18 minutes a mil (<em><a href="https://en.wikipedia.org/wiki/Maimonides"
315         * >Rambam</a></em> and others). The sun's position at 72 minutes before {@link #getSunrise sunrise} in Jerusalem
316         * on the <a href="https://kosherjava.com/2022/01/12/equinox-vs-equilux-zmanim-calculations/">around the equinox /
317         * equilux</a> is 16.1&deg; below {@link #GEOMETRIC_ZENITH}.
318         * 
319         * @see #ZENITH_16_POINT_1
320         * @see ComplexZmanimCalendar#getAlos16Point1Degrees()
321         * 
322         * @return The <code>Date</code> of dawn. If the calculation can't be computed such as northern and southern
323         *         locations even south of the Arctic Circle and north of the Antarctic Circle where the sun may not reach
324         *         low enough below the horizon for this calculation, a <code>null</code> will be returned. See detailed
325         *         explanation on top of the {@link AstronomicalCalendar} documentation.
326         */
327        public Date getAlosHashachar() {
328                return getSunriseOffsetByDegrees(ZENITH_16_POINT_1);
329        }
330
331        /**
332         * Method to return <em>alos</em> (dawn) calculated using 72 minutes before {@link #getSunrise() sunrise} or
333         * {@link #getSeaLevelSunrise() sea level sunrise} (depending on the {@link #isUseElevation()} setting). This time
334         * is based on the time to walk the distance of 4 <em>Mil</em> at 18 minutes a <em>Mil</em>. The 72 minute time (but
335         * not the concept of fixed minutes) is based on the opinion that the time of the <em>Neshef</em> (twilight between
336         * dawn and sunrise) does not vary by the time of year or location but depends on the time it takes to walk the
337         * distance of 4 <em>Mil</em>.
338         * 
339         * @return the <code>Date</code> representing the time. If the calculation can't be computed such as in the Arctic
340         *         Circle where there is at least one day a year where the sun does not rise, and one where it does not set,
341         *         a <code>null</code> will be returned. See detailed explanation on top of the {@link AstronomicalCalendar}
342         *         documentation.
343         */
344        public Date getAlos72() {
345                return getTimeOffset(getElevationAdjustedSunrise(), -72 * MINUTE_MILLIS);
346        }
347
348        /**
349         * This method returns {@link #getSunTransit() Astronomical <em>chatzos</em>} if the
350         * {@link com.kosherjava.zmanim.util.AstronomicalCalculator calculator} class used supports it and
351         * {@link #isUseAstronomicalChatzos() isUseAstronomicalChatzos()} is set to <em>true</em> or the {@link #getChatzosAsHalfDay()
352         * halfway point between sunrise and sunset} if it does not support it or it is not configured to use it. There are currently
353         * two {@link com.kosherjava.zmanim.util.AstronomicalCalculator calculators} available in the API, the default {@link
354         * com.kosherjava.zmanim.util.NOAACalculator NOAA calculator} and the {@link com.kosherjava.zmanim.util.SunTimesCalculator USNO
355         * calculator}. The USNO calculator calculates <em>chatzos</em> as halfway between sunrise and sunset (identical to six <em>shaaos
356         * zmaniyos</em> after sunrise), while the NOAACalculator calculates it more accurately as {@link #getSunTransit() astronomical
357         * <em>chatzos</em>}. See <a href="https://kosherjava.com/2020/07/02/definition-of-chatzos/">The Definition of <em>Chatzos</em></a>
358         * for a detailed explanation of the ways to calculate <em>Chatzos</em>. Since half-day <em>chatzos</em> can be <code>null</code> in
359         * the Arctic on a day when either sunrise or sunset did not happen and astronomical <em>chatzos</em> can be calculated even in that
360         * case, even if it is not configured to use astronomical <em>chatzos</em>, if half-day <em>chatzos</em> is null and astronomical
361         * <em>chatzos</em> is supported by the calculator, astronomical <em>chatzos</em> will be returned in an effort to not return a
362         * <code>null</code>.
363         * 
364         * @see AstronomicalCalendar#getSunTransit()
365         * @see #getChatzosAsHalfDay()
366         * @see #isUseAstronomicalChatzos()
367         * @see #setUseAstronomicalChatzos(boolean)
368         * @return the <code>Date</code> of <em>chatzos</em>. If the calculation can't be computed such as in the Arctic Circle
369         *         where there is at least one day where the sun does not rise, and one where it does not set, and the calculator does not
370         *         support astronomical calculations (that will never report a <code>null</code>) a <code>null</code> will be returned.
371         *         See detailed explanation on top of the {@link AstronomicalCalendar} documentation.
372         */
373        public Date getChatzos() {
374                if(useAstronomicalChatzos) {
375                        return getSunTransit(); // can be null of the calculator does not support astronomical chatzos
376                } else {
377                        Date halfDayChatzos = getChatzosAsHalfDay();
378                        if(halfDayChatzos == null) {
379                                return getSunTransit(); // can be null if the calculator does not support astronomical chatzos
380                        } else {
381                                return halfDayChatzos;
382                        }
383                }
384        }
385        
386        /**
387         * Returns <em>chatzos</em> calculated as halfway between sunrise and sunset. Many are of the opinion opinion that
388         * <em>chatzos</em> is calculated as the the midpoint between {@link #getSeaLevelSunrise sea level sunrise} and
389         * {@link #getSeaLevelSunset sea level sunset}, despite it not being the most accurate way to calculate it. A day
390         * starting at <em>alos</em> and ending at <em>tzais</em> using the same time or degree offset will also return
391         * the same time. In reality due to lengthening or shortening of day, this is not necessarily the exact midpoint of
392         * the day, but it is very close. This method allows you to use the NOAACalculator and still calculate <em>chatzos
393         * </em> as six <em>shaaos zmaniyos</em> after sunrise. There are currently two {@link
394         * com.kosherjava.zmanim.util.AstronomicalCalculator calculators} available in the API, the {@link
395         * com.kosherjava.zmanim.util.NOAACalculator} and the {@link com.kosherjava.zmanim.util.SunTimesCalculator}.
396         * The SunTimesCalculator calculates <em>chatzos</em> as halfway between sunrise and sunset (and of six <em>shaaos
397         * zmaniyos</em>), while the NOAACalculator calculates it as astronomical <em>chatzos</em> that is slightly more
398         * accurate. This method allows you to use the NOAACalculator and still calculate <em>chatzos</em> as six <em>shaaos
399         * zmaniyos</em> after sunrise. See <a href="https://kosherjava.com/2020/07/02/definition-of-chatzos/">The Definition
400         * of <em>Chatzos</em></a> for a detailed explanation of the ways to calculate <em>Chatzos</em>.
401         *
402         * @see com.kosherjava.zmanim.util.NOAACalculator#getUTCNoon(Calendar, GeoLocation)
403         * @see com.kosherjava.zmanim.util.SunTimesCalculator#getUTCNoon(Calendar, GeoLocation)
404         * @see com.kosherjava.zmanim.util.AstronomicalCalculator#getUTCNoon(Calendar, GeoLocation)
405         * @see AstronomicalCalendar#getSunTransit(Date, Date)
406         * @see #getChatzos()
407         * @see #getSunTransit()
408         * @see #isUseAstronomicalChatzos()
409         * 
410         * @return the <code>Date</code> of the latest <em>chatzos</em>. If the calculation can't be computed such
411         *         as in the Arctic Circle where there is at least one day a year where the sun does not rise, and one where
412         *         it does not set, a <code>null</code> will be returned. See detailed explanation on top of the
413         *         {@link AstronomicalCalendar} documentation.
414         */
415        public Date getChatzosAsHalfDay() {
416                return getSunTransit(getSeaLevelSunrise(), getSeaLevelSunset());
417        }
418
419        /**
420         * A generic method for calculating the latest <em>zman krias shema</em> (time to recite shema in the morning)
421         * that is 3 * <em>shaos zmaniyos</em> (temporal hours) after the start of the day, calculated using the start and
422         * end of the day passed to this method.
423         * The time from the start of day to the end of day are divided into 12 <em>shaos zmaniyos</em> (temporal hours),
424         * and the latest <em>zman krias shema</em> is calculated as 3 of those <em>shaos zmaniyos</em> after the beginning of
425         * the day. As an example, passing {@link #getSunrise() sunrise} and {@link #getSunset sunset} or {@link #getSeaLevelSunrise()
426         * sea level sunrise} and {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link #isUseElevation()}
427         * elevation setting) to this method will return <em>sof zman krias shema</em> according to the opinion of the
428         * <em><a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a></em>.
429         * 
430         * @param startOfDay
431         *            the start of day for calculating <em>zman krias shema</em>. This can be sunrise or any <em>alos</em> passed
432         *            to this method.
433         * @param endOfDay
434         *            the end of day for calculating <em>zman krias shema</em>. This can be sunset or any <em>tzais</em> passed to
435         *            this method.
436         * @return the <code>Date</code> of the latest <em>zman shema</em> based on the start and end of day times passed to this
437         *         method. If the calculation can't be computed such as in the Arctic Circle where there is at least one day
438         *         a year where the sun does not rise, and one where it does not set, a <code>null</code> will be returned. See
439         *         detailed explanation on top of the {@link AstronomicalCalendar} documentation.
440         */
441        public Date getSofZmanShma(Date startOfDay, Date endOfDay) {
442                return getShaahZmanisBasedZman(startOfDay, endOfDay, 3);
443        }
444
445        /**
446         * This method returns the latest <em>zman krias shema</em> (time to recite shema in the morning) that is 3 *
447         * {@link #getShaahZmanisGra() <em>shaos zmaniyos</em>} (solar hours) after {@link #getSunrise() sunrise} or
448         * {@link #getSeaLevelSunrise() sea level sunrise} (depending on the {@link #isUseElevation()} setting), according
449         * to the <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. 
450         *  The day is calculated from {@link #getSeaLevelSunrise() sea level sunrise} to {@link #getSeaLevelSunrise sea level
451         *  sunset} or {@link #getSunrise() sunrise} to {@link #getSunset() sunset} (depending on the {@link #isUseElevation()}
452         *  setting).
453         * 
454         * @see #getSofZmanShma(Date, Date)
455         * @see #getShaahZmanisGra()
456         * @see #isUseElevation()
457         * @see ComplexZmanimCalendar#getSofZmanShmaBaalHatanya()
458         * @return the <code>Date</code> of the latest <em>zman shema</em> according to the GRA. If the calculation can't be
459         *         computed such as in the Arctic Circle where there is at least one day a year where the sun does not rise,
460         *         and one where it does not set, a <code>null</code> will be returned. See the detailed explanation on top
461         *         of the {@link AstronomicalCalendar} documentation.
462         */
463        public Date getSofZmanShmaGRA() {
464                return getSofZmanShma(getElevationAdjustedSunrise(), getElevationAdjustedSunset());
465        }
466
467        /**
468         * This method returns the latest <em>zman krias shema</em> (time to recite shema in the morning) that is 3 *
469         * {@link #getShaahZmanisMGA() <em>shaos zmaniyos</em>} (solar hours) after {@link #getAlos72()}, according to the
470         * <a href="https://en.wikipedia.org/wiki/Avraham_Gombinern">Magen Avraham (MGA)</a>. The day is calculated
471         * from 72 minutes before {@link #getSeaLevelSunrise() sea level sunrise} to 72 minutes after {@link
472         * #getSeaLevelSunrise sea level sunset} or from 72 minutes before {@link #getSunrise() sunrise} to {@link #getSunset()
473         * sunset} (depending on the {@link #isUseElevation()} setting).
474         * 
475         * @return the <code>Date</code> of the latest <em>zman shema</em>. If the calculation can't be computed such as in
476         *         the Arctic Circle where there is at least one day a year where the sun does not rise, and one where it
477         *         does not set, a <code>null</code> will be returned. See detailed explanation on top of the
478         *         {@link AstronomicalCalendar} documentation.
479         * @see #getSofZmanShma(Date, Date)
480         * @see ComplexZmanimCalendar#getShaahZmanis72Minutes()
481         * @see ComplexZmanimCalendar#getAlos72()
482         * @see ComplexZmanimCalendar#getSofZmanShmaMGA72Minutes() that 
483         */
484        public Date getSofZmanShmaMGA() {
485                return getSofZmanShma(getAlos72(), getTzais72());
486        }
487
488        /**
489         * This method returns the <em>tzais</em> (nightfall) based on the opinion of <em>Rabbeinu Tam</em> that
490         * <em>tzais hakochavim</em> is calculated as 72 minutes, the time it takes to walk 4 <em>Mil</em> at 18 minutes
491         * a <em>Mil</em>. According to the <a href="https://en.wikipedia.org/wiki/Samuel_Loew">Machtzis Hashekel</a> in
492         * Orach Chaim 235:3, the <a href="https://en.wikipedia.org/wiki/Joseph_ben_Meir_Teomim">Pri Megadim</a> in Orach
493         * Chaim 261:2 (see the Biur Halacha) and others (see Hazmanim Bahalacha 17:3 and 17:5) the 72 minutes are standard
494         * clock minutes any time of the year in any location. Depending on the {@link #isUseElevation()} setting) a 72
495         * minute offset from  either {@link #getSunset() sunset} or {@link #getSeaLevelSunset() sea level sunset} is used.
496         * 
497         * @see ComplexZmanimCalendar#getTzais16Point1Degrees()
498         * @return the <code>Date</code> representing 72 minutes after sunset. If the calculation can't be
499         *         computed such as in the Arctic Circle where there is at least one day a year where the sun does not rise,
500         *         and one where it does not set, a <code>null</code> will be returned See detailed explanation on top of the
501         *         {@link AstronomicalCalendar} documentation.
502         */
503        public Date getTzais72() {
504                return getTimeOffset(getElevationAdjustedSunset(), 72 * MINUTE_MILLIS);
505        }
506
507        /**
508         * A method to return candle lighting time, calculated as {@link #getCandleLightingOffset()} minutes before
509         * {@link #getSeaLevelSunset() sea level sunset}. This will return the time for any day of the week, since it can be
510         * used to calculate candle lighting time for <em>Yom Tov</em> (mid-week holidays) as well. Elevation adjustments
511         * are intentionally not performed by this method, but you can calculate it by passing the elevation adjusted sunset
512         * to {@link #getTimeOffset(Date, long)}.
513         * 
514         * @return candle lighting time. If the calculation can't be computed such as in the Arctic Circle where there is at
515         *         least one day a year where the sun does not rise, and one where it does not set, a <code>null</code> will
516         *         be returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation.
517         * 
518         * @see #getSeaLevelSunset()
519         * @see #getCandleLightingOffset()
520         * @see #setCandleLightingOffset(double)
521         */
522        public Date getCandleLighting() {
523                return getTimeOffset(getSeaLevelSunset(), -getCandleLightingOffset() * MINUTE_MILLIS);
524        }
525
526        /**
527         * A generic method for calculating the latest <em>zman tfilah</em> (time to recite the morning prayers)
528         * that is 4 * <em>shaos zmaniyos</em> (temporal hours) after the start of the day, calculated using the start and
529         * end of the day passed to this method.
530         * The time from the start of day to the end of day are divided into 12 <em>shaos zmaniyos</em> (temporal hours),
531         * and <em>sof zman tfila</em> is calculated as 4 of those <em>shaos zmaniyos</em> after the beginning of the day.
532         * As an example, passing {@link #getSunrise() sunrise} and {@link #getSunset sunset} or {@link #getSeaLevelSunrise()
533         * sea level sunrise} and {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link #isUseElevation()}
534         * elevation setting) to this method will return <em>zman tfilah</em> according to the opinion of the <em><a href=
535         * "https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a></em>.
536         * 
537         * @param startOfDay
538         *            the start of day for calculating <em>zman tfilah</em>. This can be sunrise or any <em>alos</em> passed
539         *            to this method.
540         * @param endOfDay
541         *            the end of day for calculating <em>zman tfilah</em>. This can be sunset or any <em>tzais</em> passed
542         *            to this method.
543         * @return the <code>Date</code> of the latest <em>zman tfilah</em> based on the start and end of day times passed
544         *         to this method. If the calculation can't be computed such as in the Arctic Circle where there is at least
545         *         one day a year where the sun does not rise, and one where it does not set, a <code>null</code> will be
546         *         returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation.
547         */
548        public Date getSofZmanTfila(Date startOfDay, Date endOfDay) {
549                return getShaahZmanisBasedZman(startOfDay, endOfDay, 4);
550        }
551
552        /**
553         * This method returns the latest <em>zman tfila</em> (time to recite shema in the morning) that is 4 *
554         * {@link #getShaahZmanisGra() <em>shaos zmaniyos</em> }(solar hours) after {@link #getSunrise() sunrise} or
555         * {@link #getSeaLevelSunrise() sea level sunrise} (depending on the {@link #isUseElevation()} setting), according
556         * to the <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. 
557         * The day is calculated from {@link #getSeaLevelSunrise() sea level sunrise} to {@link #getSeaLevelSunrise sea level
558         * sunset} or {@link #getSunrise() sunrise} to {@link #getSunset() sunset} (depending on the {@link #isUseElevation()}
559         * setting).
560         * 
561         * @see #getSofZmanTfila(Date, Date)
562         * @see #getShaahZmanisGra()
563         * @see ComplexZmanimCalendar#getSofZmanTfilaBaalHatanya()
564         * @return the <code>Date</code> of the latest <em>zman tfilah</em>. If the calculation can't be computed such as in
565         *         the Arctic Circle where there is at least one day a year where the sun does not rise, and one where it
566         *         does not set, a <code>null</code> will be returned. See detailed explanation on top of the
567         *         {@link AstronomicalCalendar} documentation.
568         */
569        public Date getSofZmanTfilaGRA() {
570                return getSofZmanTfila(getElevationAdjustedSunrise(), getElevationAdjustedSunset());
571        }
572
573        /**
574         * This method returns the latest <em>zman tfila</em> (time to recite shema in the morning) that is 4 *
575         * {@link #getShaahZmanisMGA() <em>shaos zmaniyos</em>} (solar hours) after {@link #getAlos72()}, according to the
576         * <em><a href="https://en.wikipedia.org/wiki/Avraham_Gombinern">Magen Avraham (MGA)</a></em>. The day is calculated
577         * from 72 minutes before {@link #getSeaLevelSunrise() sea level sunrise} to 72 minutes after {@link
578         * #getSeaLevelSunrise sea level sunset} or from 72 minutes before {@link #getSunrise() sunrise} to {@link #getSunset()
579         * sunset} (depending on the {@link #isUseElevation()} setting).
580         * 
581         * @return the <code>Date</code> of the latest <em>zman tfila</em>. If the calculation can't be computed such as in
582         *         the Arctic Circle where there is at least one day a year where the sun does not rise, and one where it
583         *         does not set), a <code>null</code> will be returned. See detailed explanation on top of the
584         *         {@link AstronomicalCalendar} documentation.
585         * @see #getSofZmanTfila(Date, Date)
586         * @see #getShaahZmanisMGA()
587         * @see #getAlos72()
588         */
589        public Date getSofZmanTfilaMGA() {
590                return getSofZmanTfila(getAlos72(), getTzais72());
591        }
592
593        /**
594         * A generic method for calculating the latest <em>mincha gedola</em> (the earliest time to recite the <em>mincha1</em>
595         * prayers) that is 6.5 * <em>shaos zmaniyos</em> (temporal hours) after the start of the day, calculated using the start
596         * and end of the day passed to this method. The time from the start of day to the end of day are divided into 12
597         * <em>shaos zmaniyos</em> (temporal hours), and <em>mincha gedola</em> is calculated as 6.5 of those <em>shaos
598         * zmaniyos</em> after the beginning of the day. As an example, passing {@link #getSunrise() sunrise} and {@link #getSunset
599         * sunset} or {@link #getSeaLevelSunrise() sea level sunrise} and {@link #getSeaLevelSunset() sea level sunset} (depending
600         * on the {@link #isUseElevation()} elevation setting) to this method will return <em>mincha gedola</em> according to the
601         * opinion of the <em><a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a></em>. Alternatively, this method uses {@link
602         * #isUseAstronomicalChatzosForOtherZmanim()} to control if the time is based on 6.5 <em>sha'os zmaniyos</em> into the day
603         * mentioned above, or as half an hour <em>zmaniyos</em> based on the second half of the day after <em>chatzos</em> ({@link
604         * #getSunTransit() astronomical <em>chatzos</em>} if supported by the {@link AstronomicalCalculator calculator} and {@link
605         * #isUseAstronomicalChatzos() configured} or {@link #getChatzosAsHalfDay() <em>chatzos</em> as half a day} if not. 
606         * 
607         * @param startOfDay
608         *            the start of day for calculating <em>Mincha gedola</em>. This can be sunrise or any <em>alos</em> passed
609         *            to this method.
610         * @param endOfDay
611         *            the end of day for calculating <em>Mincha gedola</em>. This can be sunset or any <em>tzais</em> passed
612         *            to this method.
613         * @return the <code>Date</code> of the time of <em>Mincha gedola</em> based on the start and end of day times
614         *         passed to this method. If the calculation can't be computed such as in the Arctic Circle where there is
615         *         at least one day a year where the sun does not rise, and one where it does not set, a <code>null</code> will
616         *         be returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation.
617         * @see #getSunTransit()
618         * @see #getChatzosAsHalfDay()
619         * @see #getChatzos()
620         * @see #isUseAstronomicalChatzos()
621         * @see #isUseAstronomicalChatzosForOtherZmanim()
622         */
623        public Date getMinchaGedola(Date startOfDay, Date endOfDay) {
624                if(isUseAstronomicalChatzosForOtherZmanim()) {
625                        return getHalfDayBasedZman(getChatzos(), endOfDay, 0.5);
626                } else {
627                        return getShaahZmanisBasedZman(startOfDay, endOfDay, 6.5);
628                }
629        }
630
631        /**
632         * This method returns the latest <em>mincha gedola</em>,the earliest time one can pray <em>mincha</em> that is 6.5 *
633         * {@link #getShaahZmanisGra() <em>shaos zmaniyos</em>} (solar hours) after {@link #getSunrise() sunrise} or
634         * {@link #getSeaLevelSunrise() sea level sunrise} (depending on the {@link #isUseElevation()} setting), according
635         * to the <em><a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a></em>. <em>Mincha gedola</em> is the earliest
636         * time one can pray <em>mincha</em>. The Ramba"m is of the opinion that it is better to delay <em>mincha</em> until
637         * {@link #getMinchaKetana() <em>mincha ketana</em>} while the <em>Ra"sh, Tur, GRA</em> and others are of the
638         * opinion that <em>mincha</em> can be prayed <em>lechatchila</em> starting at <em>mincha gedola</em>.
639         * The day is calculated from {@link #getSeaLevelSunrise() sea level sunrise} to {@link #getSeaLevelSunrise sea level
640         * sunset} or {@link #getSunrise() sunrise} to {@link #getSunset() sunset} (depending on the {@link #isUseElevation()}
641         * setting).
642         * @todo Consider adjusting this to calculate the time as half an hour <em>zmaniyos</em> after either {@link
643         *         #getSunTransit() astronomical <em>chatzos</em>} or {@link #getChatzosAsHalfDay() <em>chatzos</em> as half a day}
644         *         for {@link AstronomicalCalculator calculators} that support it, based on {@link #isUseAstronomicalChatzos()}.
645         * 
646         * @see #getMinchaGedola(Date, Date)
647         * @see #getShaahZmanisGra()
648         * @see #getMinchaKetana()
649         * @see ComplexZmanimCalendar#getMinchaGedolaBaalHatanya()
650         * @return the <code>Date</code> of the time of mincha gedola. If the calculation can't be computed such as in the
651         *         Arctic Circle where there is at least one day a year where the sun does not rise, and one where it does
652         *         not set, a <code>null</code> will be returned. See detailed explanation on top of the
653         *         {@link AstronomicalCalendar} documentation.
654         */
655        public Date getMinchaGedola() {
656                if(isUseAstronomicalChatzosForOtherZmanim()) {
657                        return getHalfDayBasedZman(getChatzos(), getSunset(), 0.5);
658                } else {
659                        return getMinchaGedola(getElevationAdjustedSunrise(), getElevationAdjustedSunset());
660                }
661        }
662        
663        /**
664         * A generic method for calculating <em>samuch lemincha ketana</em>, / near <em>mincha ketana</em> time that is half
665         * an hour before {@link #getMinchaKetana(Date, Date)}  or 9 * <em>shaos zmaniyos</em> (temporal hours) after the
666         * start of the day, calculated using the start and end of the day passed to this method.
667         * The time from the start of day to the end of day are divided into 12 <em>shaos zmaniyos</em> (temporal hours), and
668         * <em>samuch lemincha ketana</em> is calculated as 9 of those <em>shaos zmaniyos</em> after the beginning of the day.
669         * For example, passing {@link #getSunrise() sunrise} and {@link #getSunset sunset} or {@link #getSeaLevelSunrise() sea
670         * level sunrise} and {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link #isUseElevation()} elevation
671         * setting) to this method will return <em>samuch lemincha ketana</em> according to the opinion of the
672         * <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>.
673         * 
674         * @param startOfDay
675         *            the start of day for calculating <em>samuch lemincha ketana</em>. This can be sunrise or any <em>alos</em>
676         *            passed to to this method.
677         * @param endOfDay
678         *            the end of day for calculating <em>samuch lemincha ketana</em>. This can be sunset or any <em>tzais</em>
679         *            passed to this method.
680         * @return the <code>Date</code> of the time of <em>Mincha ketana</em> based on the start and end of day times
681         *         passed to this method. If the calculation can't be computed such as in the Arctic Circle where there is
682         *         at least one day a year where the sun does not rise, and one where it does not set, a <code>null</code> will
683         *         be returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation.
684         *
685         * @see ComplexZmanimCalendar#getSamuchLeMinchaKetanaGRA()
686         * @see ComplexZmanimCalendar#getSamuchLeMinchaKetana16Point1Degrees()
687         * @see ComplexZmanimCalendar#getSamuchLeMinchaKetana72Minutes()
688         */
689        public Date getSamuchLeMinchaKetana(Date startOfDay, Date endOfDay) {
690                return getShaahZmanisBasedZman(startOfDay, endOfDay, 9);
691        }
692
693        /**
694         * A generic method for calculating <em>mincha ketana</em>, (the preferred time to recite the mincha prayers in
695         * the opinion of the <em><a href="https://en.wikipedia.org/wiki/Maimonides">Rambam</a></em> and others) that is
696         * 9.5 * <em>shaos zmaniyos</em> (temporal hours) after the start of the day, calculated using the start and end
697         * of the day passed to this method.
698         * The time from the start of day to the end of day are divided into 12 <em>shaos zmaniyos</em> (temporal hours), and
699         * <em>mincha ketana</em> is calculated as 9.5 of those <em>shaos zmaniyos</em> after the beginning of the day. As an
700         * example, passing {@link #getSunrise() sunrise} and {@link #getSunset sunset} or {@link #getSeaLevelSunrise() sea
701         * level sunrise} and {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link #isUseElevation()}
702         * elevation setting) to this method will return <em>mincha ketana</em> according to the opinion of the
703         * <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>.
704         * 
705         * @param startOfDay
706         *            the start of day for calculating <em>Mincha ketana</em>. This can be sunrise or any <em>alos</em> passed
707         *            to this method.
708         * @param endOfDay
709         *            the end of day for calculating <em>Mincha ketana</em>. This can be sunset or any <em>tzais</em> passed to
710         *            this method.
711         * @return the <code>Date</code> of the time of <em>Mincha ketana</em> based on the start and end of day times
712         *         passed to this method. If the calculation can't be computed such as in the Arctic Circle where there is
713         *         at least one day a year where the sun does not rise, and one where it does not set, a <code>null</code> will
714         *         be returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation.
715         */
716        public Date getMinchaKetana(Date startOfDay, Date endOfDay) {
717                return getShaahZmanisBasedZman(startOfDay, endOfDay, 9.5);
718        }
719
720        /**
721         * This method returns <em>mincha ketana</em>,the preferred earliest time to pray <em>mincha</em> in the
722         * opinion of the <em><a href="https://en.wikipedia.org/wiki/Maimonides">Rambam</a></em> and others, that is 9.5
723         * * {@link #getShaahZmanisGra() <em>shaos zmaniyos</em>} (solar hours) after {@link #getSunrise() sunrise} or
724         * {@link #getSeaLevelSunrise() sea level sunrise} (depending on the {@link #isUseElevation()} setting), according
725         * to the <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. For more information on this see the
726         * documentation on {@link #getMinchaGedola() <em>mincha gedola</em>}.
727         * The day is calculated from {@link #getSeaLevelSunrise() sea level sunrise} to {@link #getSeaLevelSunrise sea level
728         * sunset} or {@link #getSunrise() sunrise} to {@link #getSunset() sunset} (depending on the {@link #isUseElevation()}
729         * setting.
730         * 
731         * @see #getMinchaKetana(Date, Date)
732         * @see #getShaahZmanisGra()
733         * @see #getMinchaGedola()
734         * @see ComplexZmanimCalendar#getMinchaKetanaBaalHatanya()
735         * @return the <code>Date</code> of the time of mincha ketana. If the calculation can't be computed such as in the
736         *         Arctic Circle where there is at least one day a year where the sun does not rise, and one where it does
737         *         not set, a <code>null</code> will be returned. See detailed explanation on top of the
738         *         {@link AstronomicalCalendar} documentation.
739         */
740        public Date getMinchaKetana() {
741                return getMinchaKetana(getElevationAdjustedSunrise(), getElevationAdjustedSunset());
742        }
743
744        /**
745         * A generic method for calculating <em>plag hamincha</em> (the earliest time that Shabbos can be started) that is
746         * 10.75 hours after the start of the day, (or 1.25 hours before the end of the day) based on the start and end of
747         * the day passed to the method.
748         * The time from the start of day to the end of day are divided into 12 <em>shaos zmaniyos</em> (temporal hours), and
749         * <em>plag hamincha</em> is calculated as 10.75 of those <em>shaos zmaniyos</em> after the beginning of the day. As an
750         * example, passing {@link #getSunrise() sunrise} and {@link #getSunset sunset} or {@link #getSeaLevelSunrise() sea level
751         * sunrise} and {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link #isUseElevation()} elevation
752         * setting) to this method will return <em>plag mincha</em> according to the opinion of the
753         * <em><a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a></em>.
754         * 
755         * @param startOfDay
756         *            the start of day for calculating plag. This can be sunrise or any <em>alos</em> passed to this method.
757         * @param endOfDay
758         *            the end of day for calculating plag. This can be sunset or any <em>tzais</em> passed to this method.
759         * @return the <code>Date</code> of the time of <em>plag hamincha</em> based on the start and end of day times
760         *         passed to this method. If the calculation can't be computed such as in the Arctic Circle where there is
761         *         at least one day a year where the sun does not rise, and one where it does not set, a <code>null</code>
762         *         will be returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation.
763         */
764        public Date getPlagHamincha(Date startOfDay, Date endOfDay) {
765                return getShaahZmanisBasedZman(startOfDay, endOfDay, 10.75);
766        }
767
768        /**
769         * This method returns <em>plag hamincha</em>, that is 10.75 * {@link #getShaahZmanisGra() <em>shaos zmaniyos</em>}
770         * (solar hours) after {@link #getSunrise() sunrise} or {@link #getSeaLevelSunrise() sea level sunrise} (depending on
771         * the {@link #isUseElevation()} setting), according to the <em><a href="https://en.wikipedia.org/wiki/Vilna_Gaon"
772         * >GRA</a></em>. Plag hamincha is the earliest time that <em>Shabbos</em> can be started.
773         * The day is calculated from {@link #getSeaLevelSunrise() sea level sunrise} to {@link #getSeaLevelSunrise sea level
774         * sunset} or {@link #getSunrise() sunrise} to {@link #getSunset() sunset} (depending on the {@link #isUseElevation()}
775         * 
776         * @see #getPlagHamincha(Date, Date)
777         * @see ComplexZmanimCalendar#getPlagHaminchaBaalHatanya()
778         * @return the <code>Date</code> of the time of <em>plag hamincha</em>. If the calculation can't be computed such as
779         *         in the Arctic Circle where there is at least one day a year where the sun does not rise, and one where it
780         *         does not set, a <code>null</code> will be returned. See detailed explanation on top of the
781         *         {@link AstronomicalCalendar} documentation.
782         */
783        public Date getPlagHamincha() {
784                return getPlagHamincha(getElevationAdjustedSunrise(), getElevationAdjustedSunset());
785        }
786
787        /**
788         * A method that returns a <em>shaah zmanis</em> ({@link #getTemporalHour(Date, Date) temporal hour}) according to
789         * the opinion of the <em><a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a></em>. This calculation divides
790         * the day based on the opinion of the <em>GRA</em> that the day runs from from {@link #getSeaLevelSunrise() sea
791         * level sunrise} to {@link #getSeaLevelSunrise sea level sunset} or {@link #getSunrise() sunrise} to
792         * {@link #getSunset() sunset} (depending on the {@link #isUseElevation()} setting). The day is split into 12 equal
793         * parts with each one being a <em>shaah zmanis</em>. This method is similar to {@link #getTemporalHour}, but can
794         * account for elevation.
795         * 
796         * @return the <code>long</code> millisecond length of a <em>shaah zmanis</em> calculated from sunrise to sunset.
797         *         If the calculation can't be computed such as in the Arctic Circle where there is at least one day a year
798         *         where the sun does not rise, and one where it does not set, {@link Long#MIN_VALUE} will be returned. See
799         *         detailed explanation on top of the {@link AstronomicalCalendar} documentation.
800         * @see #getTemporalHour(Date, Date)
801         * @see #getSeaLevelSunrise()
802         * @see #getSeaLevelSunset()
803         * @see ComplexZmanimCalendar#getShaahZmanisBaalHatanya()
804         */
805        public long getShaahZmanisGra() {
806                return getTemporalHour(getElevationAdjustedSunrise(), getElevationAdjustedSunset());
807        }
808
809        /**
810         * A method that returns a <em>shaah zmanis</em> (temporal hour) according to the opinion of the <em><a href=
811         * "https://en.wikipedia.org/wiki/Avraham_Gombinern">Magen Avraham (MGA)</a></em> based on a 72 minutes <em>alos</em>
812         * and <em>tzais</em>. This calculation divides the day that runs from dawn to dusk (for <em>sof zman krias shema</em> and
813         * <em>tfila</em>). Dawn for this calculation is 72 minutes before {@link #getSunrise() sunrise} or {@link #getSeaLevelSunrise()
814         * sea level sunrise} (depending on the {@link #isUseElevation()} elevation setting) and dusk is 72 minutes after {@link
815         * #getSunset sunset} or {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link #isUseElevation()} elevation
816         * setting). This day is split into 12 equal parts with each part being a <em>shaah zmanis</em>. Alternate methods of calculating
817         * a <em>shaah zmanis</em> according to the Magen Avraham (MGA) are available in the subclass {@link ComplexZmanimCalendar}.
818         * 
819         * @return the <code>long</code> millisecond length of a <em>shaah zmanis</em>. If the calculation can't be computed
820         *         such as in the Arctic Circle where there is at least one day a year where the sun does not rise, and one
821         *         where it does not set, {@link Long#MIN_VALUE} will be returned. See detailed explanation on top of the
822         *         {@link AstronomicalCalendar} documentation.
823         */
824        public long getShaahZmanisMGA() {
825                return getTemporalHour(getAlos72(), getTzais72());
826        }
827
828        /**
829         * Default constructor will set a default {@link GeoLocation#GeoLocation()}, a default
830         * {@link AstronomicalCalculator#getDefault() AstronomicalCalculator} and default the calendar to the current date.
831         * 
832         * @see AstronomicalCalendar#AstronomicalCalendar()
833         */
834        public ZmanimCalendar() {
835                super();
836        }
837
838        /**
839         * A constructor that takes a {@link GeoLocation} as a parameter.
840         * 
841         * @param location
842         *            the location
843         */
844        public ZmanimCalendar(GeoLocation location) {
845                super(location);
846        }
847
848        /**
849         * A method to get the offset in minutes before {@link AstronomicalCalendar#getSeaLevelSunset() sea level sunset} which
850         * is used in calculating candle lighting time. The default time used is 18 minutes before sea level sunset. Some
851         * calendars use 15 minutes, while the custom in Jerusalem is to use a 40 minute offset. Please check the local custom
852         * for candle lighting time.
853         * 
854         * @return Returns the currently set candle lighting offset in minutes.
855         * @see #getCandleLighting()
856         * @see #setCandleLightingOffset(double)
857         */
858        public double getCandleLightingOffset() {
859                return candleLightingOffset;
860        }
861
862        /**
863         * A method to set the offset in minutes before {@link AstronomicalCalendar#getSeaLevelSunset() sea level sunset} that is
864         * used in calculating candle lighting time. The default time used is 18 minutes before sunset. Some calendars use 15
865         * minutes, while the custom in Jerusalem is to use a 40 minute offset.
866         * 
867         * @param candleLightingOffset
868         *            The candle lighting offset to set in minutes.
869         * @see #getCandleLighting()
870         * @see #getCandleLightingOffset()
871         */
872        public void setCandleLightingOffset(double candleLightingOffset) {
873                this.candleLightingOffset = candleLightingOffset;
874        }
875        
876        /**
877         * This is a utility method to determine if the current Date (date-time) passed in has a <em>melacha</em> (work) prohibition.
878         * Since there are many opinions on the time of <em>tzais</em>, the <em>tzais</em> for the current day has to be passed to this
879         * class. Sunset is the classes current day's {@link #getElevationAdjustedSunset() elevation adjusted sunset} that observes the
880         * {@link #isUseElevation()} settings. The {@link JewishCalendar#getInIsrael()} will be set by the inIsrael parameter.
881         * 
882         * @param currentTime the current time
883         * @param tzais the time of tzais
884         * @param inIsrael whether to use Israel holiday scheme or not
885         * 
886         * @return true if <em>melacha</em> is prohibited or false if it is not.
887         * 
888         * @see JewishCalendar#isAssurBemelacha()
889         * @see JewishCalendar#hasCandleLighting()
890         * @see JewishCalendar#setInIsrael(boolean)
891         */
892        public boolean isAssurBemlacha(Date currentTime, Date tzais, boolean inIsrael) {
893                JewishCalendar jewishCalendar = new JewishCalendar();
894                jewishCalendar.setGregorianDate(getCalendar().get(Calendar.YEAR), getCalendar().get(Calendar.MONTH),
895                                getCalendar().get(Calendar.DAY_OF_MONTH));
896                jewishCalendar.setInIsrael(inIsrael);
897                
898                if(jewishCalendar.hasCandleLighting() && currentTime.compareTo(getElevationAdjustedSunset()) >= 0) { //erev shabbos, YT or YT sheni and after shkiah
899                        return true;
900                }
901                
902                if(jewishCalendar.isAssurBemelacha()  && currentTime.compareTo(tzais) <= 0) { //is shabbos or YT and it is before tzais
903                        return true;
904                }
905                
906                return false;
907        }
908
909        /**
910         * A generic utility method for calculating any <em>shaah zmanis</em> (temporal hour) based <em>zman</em> with the
911         * day defined as the start and end of day (or night) and the number of <em>shaahos zmaniyos</em> passed to the
912         * method. This simplifies the code in other methods such as {@link #getPlagHamincha(Date, Date)} and cuts down on
913         * code replication. As an example, passing {@link #getSunrise() sunrise} and {@link #getSunset sunset} or {@link
914         * #getSeaLevelSunrise() sea level sunrise} and {@link #getSeaLevelSunset() sea level sunset} (depending on the
915         * {@link #isUseElevation()} elevation setting) and 10.75 hours to this method will return <em>plag mincha</em>
916         * according to the opinion of the <em><a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a></em>.
917         * 
918         * @param startOfDay
919         *            the start of day for calculating the <em>zman</em>. This can be sunrise or any <em>alos</em> passed
920         *            to this method.
921         * @param endOfDay
922         *            the end of day for calculating the <em>zman</em>. This can be sunset or any <em>tzais</em> passed to
923         *            this method.
924         * @param hours
925         *            the number of <em>shaahos zmaniyos</em> (temporal hours) to offset from the start of day
926         * @return the <code>Date</code> of the time of <em>zman</em> with the <em>shaahos zmaniyos</em> (temporal hours)
927         *         in the day offset from the start of day passed to this method. If the calculation can't be computed such
928         *         as in the Arctic Circle where there is at least one day a year where the sun does not rise, and one
929         *         where it does not set, a <code>null</code> will be  returned. See detailed explanation on top of the
930         *         {@link AstronomicalCalendar} documentation.
931         */
932        public Date getShaahZmanisBasedZman(Date startOfDay, Date endOfDay, double hours) {
933                long shaahZmanis = getTemporalHour(startOfDay, endOfDay);
934                return getTimeOffset(startOfDay, shaahZmanis * hours);
935        }
936        
937        /**
938         * A utility method that returns the percentage of a <em>shaah zmanis</em> after sunset (or before sunrise) for a given degree
939         * offset. For the <a href="https://kosherjava.com/2022/01/12/equinox-vs-equilux-zmanim-calculations/">equilux</a> where there
940         * is a 720-minute day, passing 16.1&deg; for the location of Jerusalem will return about 1.2. This will work for any location
941         * or date, but will typically only be of interest at the equinox/equilux to calculate the percentage of a <em>shaah zmanis</em>
942         * for those who want to use the <a href="https://en.wikipedia.org/wiki/Abraham_Cohen_Pimentel">Minchas Cohen</a> in Ma'amar 2:4
943         * and the <a href="https://en.wikipedia.org/wiki/Hezekiah_da_Silva">Pri Chadash</a> who calculate <em>tzais</em> as a percentage
944         * of the day after sunset. While the Minchas Cohen only applies this to 72 minutes or a 1/10 of the day around the world (based
945         * on the equinox / equilux in Israel, this method allows calculations for any degrees level for any location.
946         * 
947         * @param degrees
948         *            the number of degrees below the horizon after sunset.
949         * @param sunset
950         *            if <code>true</code> the calculation should be degrees after sunset, or if <code>false</code>, degrees before sunrise.
951         * @return the <code>double</code> percentage of a <em>sha'ah zmanis</em> for a given set of degrees below the astronomical horizon
952         *         for the current calendar.  If the calculation can't be computed a {@link Double#MIN_VALUE} will be returned. See detailed
953         *         explanation on top of the page.
954         */
955        public double getPercentOfShaahZmanisFromDegrees(double degrees, boolean sunset) {
956                Date seaLevelSunrise = getSeaLevelSunrise();
957                Date seaLevelSunset = getSeaLevelSunset();
958                Date twilight = null;
959                if(sunset) {
960                        twilight = getSunsetOffsetByDegrees(GEOMETRIC_ZENITH + degrees);
961                } else {
962                        twilight = getSunriseOffsetByDegrees(GEOMETRIC_ZENITH + degrees);
963                }
964                if(seaLevelSunrise == null || seaLevelSunset == null || twilight == null) {
965                        return Double.MIN_VALUE;
966                }
967                double shaahZmanis = (seaLevelSunset.getTime() - seaLevelSunrise.getTime()) / 12.0;
968                long riseSetToTwilight;
969                if(sunset) {
970                        riseSetToTwilight = twilight.getTime() - seaLevelSunset.getTime();
971                } else {
972                        riseSetToTwilight = seaLevelSunrise.getTime() - twilight.getTime();
973                }
974                return riseSetToTwilight / shaahZmanis;
975        }
976        
977        /**
978         * A utility method to calculate <em>zmanim</em> based on <a href="https://en.wikipedia.org/wiki/Moshe_Feinstein">Rav Moshe
979         * Feinstein</a> and others as calculated in <a href="https://en.wikipedia.org/wiki/Mesivtha_Tifereth_Jerusalem">MTJ</a>, <a href=
980         * "https://en.wikipedia.org/wiki/Mesivtha_Tifereth_Jerusalem">Yeshiva of Staten Island</a>, and Camp Yeshiva
981         * of Staten Island and other calendars. The day is split in two, from <em>alos</em> / sunrise to <em>chatzos</em>, and the
982         * second half of the day, from <em>chatzos</em> to sunset / <em>tzais</em>. Morning based times are calculated. based on the first
983         * 6 hours of the day, and afternoon times based on the second half of the day. As an example, passing 0.5, a start of
984         * <em>chatzos</em> and an end of day as sunset will return the time of <em>mincha gedola</em> GRA as half an hour <em>zmanis</em>
985         * based on the second half of the day. Some <em>zmanim</em> calculations can be based on subtracting <em>sha'os zmaniyos</em>
986         * from the end of the day, and that is supported by passing a negative hour to this method.
987         * 
988         * @param startOfHalfDay
989         *            The start of the half day. This would be <em>alos</em> or sunrise for morning based times such as <em>sof zman krias
990         *            shema</em> and <em>chatzos</em> for afternoon based times such as <em>mincha gedola</em>.
991         * @param endOfHalfDay
992         *            The end of the half day. This would be <em>chatzos</em> for morning based times  such as <em>sof zman krias shema</em>
993         *            and sunset or <em>tzais</em> for afternoon based times such as <em>mincha gedola</em>.
994         * @param hours
995         *            The number of <em>sha'os zmaniyos</em> (hours) to offset the beginning of the first or second half of the day. For example,
996         *            3 for <em>sof zman Shma</em>, 0.5 for <em>mincha gedola</em> (half an hour after <em>chatzos</em>) and 4.75 for <em>plag
997         *            hamincha</em>. If the number of hours is negative, it will subtract the number of <em>sha'os zmaniyos</em> from the end
998         *            of the day.
999         * 
1000         * @return the <code>Date</code> of <em>zman</em> based on calculation of the first or second half of the day. If the
1001         *         calculation can't be computed such as in the Arctic Circle where there is at least one day a year where the
1002         *         sun does not rise, and one where it does not set, a <code>null</code> will be returned. See detailed explanation
1003         *         on top of the {@link AstronomicalCalendar} documentation.
1004         *
1005         * @see ComplexZmanimCalendar#getFixedLocalChatzos()
1006         */
1007        public Date getHalfDayBasedZman(Date startOfHalfDay, Date endOfHalfDay, double hours) {
1008                if (startOfHalfDay == null || endOfHalfDay == null) {
1009                        return null;
1010                }
1011                long shaahZmanis = getHalfDayBasedShaahZmanis(startOfHalfDay, endOfHalfDay);
1012                if(shaahZmanis == Long.MIN_VALUE) { //defensive, should not be needed
1013                        return null;
1014                }
1015                if(hours >= 0) { // forward from start a day
1016                        return getTimeOffset(startOfHalfDay, shaahZmanis * hours);
1017                } else { // subtract from end of day
1018                        return getTimeOffset(endOfHalfDay, shaahZmanis * hours);
1019                }
1020        }
1021        
1022        /**
1023         * A utility method to calculate the length of a <em>sha'ah zmanis</em> based on 1/6 of a 6 hour day.
1024         * @param startOfHalfDay The start of the half-day. This would be <em>alos</em> or sunrise for the first half of the day,
1025         *            or <em>chatzos</em> for the second half of the day.
1026         * @param endOfHalfDay The end of the half-day. This would be <em>chatzos</em> for the first half of the day, or sunset or
1027         *            <em>tzais</em> for the second half of the day.
1028         * @return The <code>long</code> millisecond length of a <em>shaah zmanis</em> based on 1/6 of a half-day. If the calculation
1029         *         can't be computed such as in the Arctic Circle where there is at least one day a year where the sun does not rise,
1030         *         and one where it does not set, {@link Long#MIN_VALUE} will be returned. See detailed explanation on top of the
1031         *         {@link AstronomicalCalendar} documentation.
1032         * @see #getHalfDayBasedZman(Date, Date, double)
1033         * @see #isUseAstronomicalChatzosForOtherZmanim()
1034         */
1035        public long getHalfDayBasedShaahZmanis(Date startOfHalfDay, Date endOfHalfDay) {
1036                if (startOfHalfDay == null || endOfHalfDay == null) {
1037                        return Long.MIN_VALUE;
1038                }
1039                return (endOfHalfDay.getTime() - startOfHalfDay.getTime()) / 6;
1040        }
1041}