001/*
002 * Zmanim Java API
003 * Copyright (C) 2004-2025 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 - 2025
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 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>shaos zmaniyos</em> after sunrise, but the <em>shaos
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>shaos zmaniyos</em> after sunrise. {@link #getPlagHamincha() <em>Plag
141         * hamincha</em>} would be calculated as 4.75 <em>shaos zmaniyos</em> after astronomical <em>chatzos</em> as opposed to 10.75
142         * <em>shaos 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 autumn 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>shaos zmaniyos</em> after sunrise, but the <em>shaos
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>shaos zmaniyos</em> after sunrise. {@link #getPlagHamincha() <em>Plag
194         * hamincha</em>} would be calculated as 4.75 <em>shaos zmaniyos</em> after astronomical <em>chatzos</em> as opposed to 10.75
195         * <em>shaos 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 <a href=
221         * "https://en.wikipedia.org/wiki/Biblical_and_Talmudic_units_of_measurement">mil</a> at 18 minutes a mil (<a href=
222         * "https://en.wikipedia.org/wiki/Maimonides">Rambam</a> and others). The sun's position below the horizon 72 minutes
223         * before {@link #getSunrise() sunrise} in Jerusalem <a href=
224         * "https://kosherjava.com/2022/01/12/equinox-vs-equilux-zmanim-calculations/">around the equinox / equilux</a> is
225         * 16.1&deg; below {@link #GEOMETRIC_ZENITH geometric zenith}.
226         * 
227         * @see #getAlosHashachar()
228         * @see ComplexZmanimCalendar#getAlos16Point1Degrees()
229         * @see ComplexZmanimCalendar#getTzais16Point1Degrees()
230         * @see ComplexZmanimCalendar#getSofZmanShmaMGA16Point1Degrees()
231         * @see ComplexZmanimCalendar#getSofZmanTfilaMGA16Point1Degrees()
232         * @see ComplexZmanimCalendar#getMinchaGedola16Point1Degrees()
233         * @see ComplexZmanimCalendar#getMinchaKetana16Point1Degrees()
234         * @see ComplexZmanimCalendar#getPlagHamincha16Point1Degrees()
235         * @see ComplexZmanimCalendar#getPlagAlos16Point1ToTzaisGeonim7Point083Degrees()
236         * @see ComplexZmanimCalendar#getSofZmanShmaAlos16Point1ToSunset()
237         */
238        protected static final double ZENITH_16_POINT_1 = GEOMETRIC_ZENITH + 16.1;
239
240        /**
241         * The zenith of 8.5&deg; below geometric zenith (90&deg;). This calculation is used for calculating <em>alos</em>
242         * (dawn) and <em>tzais</em> (nightfall) in some opinions. This calculation is based on the sun's position below the
243         * horizon 36 minutes after {@link #getSunset() sunset} in Jerusalem <a href=
244         * "https://kosherjava.com/2022/01/12/equinox-vs-equilux-zmanim-calculations/">around the equinox / equilux</a>, which
245         * is 8.5&deg; below {@link #GEOMETRIC_ZENITH geometric zenith}. The <em><a href=
246         * "https://www.worldcat.org/oclc/29283612">Ohr Meir</a></em> considers this the time that 3 small stars are visible,
247         * which is later than the required 3 medium stars.
248         * 
249         * @see #getTzais()
250         * @see ComplexZmanimCalendar#getTzaisGeonim8Point5Degrees()
251         */
252        protected static final double ZENITH_8_POINT_5 = GEOMETRIC_ZENITH + 8.5;
253
254        /**
255         * The default <em>Shabbos</em> candle lighting offset is 18 minutes. This can be changed via the
256         * {@link #setCandleLightingOffset(double)} and retrieved by the {@link #getCandleLightingOffset()}.
257         */
258        private double candleLightingOffset = 18;
259        
260        /**
261         * This method will return {@link #getSeaLevelSunrise() sea level sunrise} if {@link #isUseElevation()} is false (the
262         * default), or elevation adjusted {@link AstronomicalCalendar#getSunrise()} if it is true. This allows relevant <em>zmanim</em>
263         * in this and extending classes (such as the {@link ComplexZmanimCalendar}) to automatically adjust to the elevation setting.
264         * 
265         * @return {@link #getSeaLevelSunrise()} if {@link #isUseElevation()} is false (the default), or elevation adjusted
266         *         {@link AstronomicalCalendar#getSunrise()} if it is true.
267         * @see com.kosherjava.zmanim.AstronomicalCalendar#getSunrise()
268         */
269        protected Date getElevationAdjustedSunrise() {
270                if (isUseElevation()) {
271                        return super.getSunrise();
272                }
273                return getSeaLevelSunrise();
274        }
275        
276        /**
277         * This method will return {@link #getSeaLevelSunrise() sea level sunrise} if {@link #isUseElevation()} is false (the default),
278         * or elevation adjusted {@link AstronomicalCalendar#getSunrise()} if it is true. This allows relevant <em>zmanim</em>
279         * in this and extending classes (such as the {@link ComplexZmanimCalendar}) to automatically adjust to the elevation setting.
280         * 
281         * @return {@link #getSeaLevelSunset()} if {@link #isUseElevation()} is false (the default), or elevation adjusted
282         *         {@link AstronomicalCalendar#getSunset()} if it is true.
283         * @see com.kosherjava.zmanim.AstronomicalCalendar#getSunset()
284         */
285        protected Date getElevationAdjustedSunset() {
286                if (isUseElevation()) {
287                        return super.getSunset();
288                }
289                return getSeaLevelSunset();
290        }
291
292        /**
293         * A method that returns <em>tzais</em> (nightfall) when the sun is {@link #ZENITH_8_POINT_5 8.5&deg;} below the
294         * {@link #GEOMETRIC_ZENITH geometric horizon} (90&deg;) after {@link #getSunset() sunset}, a time that Rabbi Meir
295         * Posen in his the <em><a href="https://www.worldcat.org/oclc/29283612">Ohr Meir</a></em> calculated that 3 small
296         * stars are visible, which is later than the required 3 medium stars. See the {@link #ZENITH_8_POINT_5} constant.
297         * 
298         * @see #ZENITH_8_POINT_5
299         * 
300         * @return The <code>Date</code> of nightfall. If the calculation can't be computed such as northern and southern
301         *         locations even south of the Arctic Circle and north of the Antarctic Circle where the sun may not reach
302         *         low enough below the horizon for this calculation, a <code>null</code> will be returned. See detailed
303         *         explanation on top of the {@link AstronomicalCalendar} documentation.
304         * @see #ZENITH_8_POINT_5
305         * ComplexZmanimCalendar#getTzaisGeonim8Point5Degrees() that returns an identical time to this generic <em>tzais</em>
306         */
307        public Date getTzais() {
308                return getSunsetOffsetByDegrees(ZENITH_8_POINT_5);
309        }
310
311        /**
312         * Returns <em>alos</em> (dawn) based on the time when the sun is {@link #ZENITH_16_POINT_1 16.1&deg;} below the
313         * eastern {@link #GEOMETRIC_ZENITH geometric horizon} before {@link #getSunrise() sunrise}. This is based on the
314         * calculation that the time between dawn and sunrise (and sunset to nightfall) is 72 minutes, the time that is
315         * takes to walk 4 <a href="https://en.wikipedia.org/wiki/Biblical_and_Talmudic_units_of_measurement">mil</a> at
316         * 18 minutes a mil (<a href="https://en.wikipedia.org/wiki/Maimonides">Rambam</a> and others). The sun's position
317         * below the horizon 72 minutes before {@link #getSunrise() sunrise} in Jerusalem on the <a href=
318         * "https://kosherjava.com/2022/01/12/equinox-vs-equilux-zmanim-calculations/">around the equinox / equilux</a> is
319         * 16.1&deg; below {@link #GEOMETRIC_ZENITH}.
320         * 
321         * @see #ZENITH_16_POINT_1
322         * @see ComplexZmanimCalendar#getAlos16Point1Degrees()
323         * 
324         * @return The <code>Date</code> of dawn. If the calculation can't be computed such as northern and southern
325         *         locations even south of the Arctic Circle and north of the Antarctic Circle where the sun may not reach
326         *         low enough below the horizon for this calculation, a <code>null</code> will be returned. See detailed
327         *         explanation on top of the {@link AstronomicalCalendar} documentation.
328         */
329        public Date getAlosHashachar() {
330                return getSunriseOffsetByDegrees(ZENITH_16_POINT_1);
331        }
332
333        /**
334         * Method to return <em>alos</em> (dawn) calculated as 72 minutes before {@link #getSunrise() sunrise} or
335         * {@link #getSeaLevelSunrise() sea level sunrise} (depending on the {@link #isUseElevation()} setting). This time
336         * is based on the time to walk the distance of 4 <a href=
337         * "https://en.wikipedia.org/wiki/Biblical_and_Talmudic_units_of_measurement">mil</a> at 18 minutes a mil. The
338         * 72-minute time (but not the concept of fixed minutes) is based on the opinion that the time of the <em>Neshef</em>
339         * (twilight between dawn and sunrise) does not vary by the time of year or location but depends on the time it takes
340         * to walk the distance of 4 mil.
341         * 
342         * @return the <code>Date</code> representing the time. If the calculation can't be computed such as in the Arctic
343         *         Circle where there is at least one day a year where the sun does not rise, and one where it does not set,
344         *         a <code>null</code> will be returned. See detailed explanation on top of the {@link AstronomicalCalendar}
345         *         documentation.
346         */
347        public Date getAlos72() {
348                return getTimeOffset(getElevationAdjustedSunrise(), -72 * MINUTE_MILLIS);
349        }
350
351        /**
352         * This method returns {@link #getSunTransit() Astronomical <em>chatzos</em>} if the
353         * {@link com.kosherjava.zmanim.util.AstronomicalCalculator calculator} class used supports it and
354         * {@link #isUseAstronomicalChatzos() isUseAstronomicalChatzos()} is set to <em>true</em> or the {@link #getChatzosAsHalfDay()
355         * halfway point between sunrise and sunset} if it does not support it, or it is not configured to use it. There are currently
356         * two {@link com.kosherjava.zmanim.util.AstronomicalCalculator calculators} available in the API, the default {@link
357         * com.kosherjava.zmanim.util.NOAACalculator NOAA calculator} and the {@link com.kosherjava.zmanim.util.SunTimesCalculator USNO
358         * calculator}. The USNO calculator calculates <em>chatzos</em> as halfway between sunrise and sunset (identical to six <em>shaos
359         * zmaniyos</em> after sunrise), while the NOAACalculator calculates it more accurately as {@link #getSunTransit() astronomical
360         * <em>chatzos</em>}. See <a href="https://kosherjava.com/2020/07/02/definition-of-chatzos/">The Definition of <em>Chatzos</em></a>
361         * for a detailed explanation of the ways to calculate <em>Chatzos</em>. Since half-day <em>chatzos</em> can be <code>null</code> in
362         * the Arctic on a day when either sunrise or sunset did not happen and astronomical <em>chatzos</em> can be calculated even in the
363         * Arctic, if half-day <em>chatzos</em> calculates as <code>null</code> and astronomical <em>chatzos</em> is supported by the
364         * calculator, astronomical <em>chatzos</em> will be returned to avoid returning a <code>null</code>.
365         * 
366         * @see AstronomicalCalendar#getSunTransit()
367         * @see #getChatzosAsHalfDay()
368         * @see #isUseAstronomicalChatzos()
369         * @see #setUseAstronomicalChatzos(boolean)
370         * @return the <code>Date</code> of <em>chatzos</em>. If the calculation can't be computed such as in the Arctic Circle
371         *         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
372         *         support astronomical calculations (that will never report a <code>null</code>) a <code>null</code> will be returned.
373         *         See detailed explanation on top of the {@link AstronomicalCalendar} documentation.
374         */
375        public Date getChatzos() {
376                if (useAstronomicalChatzos) {
377                        return getSunTransit(); // can be null of the calculator does not support astronomical chatzos
378                } else {
379                        Date halfDayChatzos = getChatzosAsHalfDay();
380                        if (halfDayChatzos == null) {
381                                return getSunTransit(); // can be null if the calculator does not support astronomical chatzos
382                        } else {
383                                return halfDayChatzos;
384                        }
385                }
386        }
387        
388        /**
389         * Returns <em>chatzos</em> calculated as halfway between sunrise and sunset. Many are of the opinion that
390         * <em>chatzos</em> is calculated as the midpoint between {@link #getSeaLevelSunrise() sea level sunrise} and
391         * {@link #getSeaLevelSunset() sea level sunset}, despite it not being the most accurate way to calculate it. A day
392         * starting at <em>alos</em> and ending at <em>tzais</em> using the same time or degree offset will also return
393         * the same time. In reality due to lengthening or shortening of day, this is not necessarily the exact midpoint of
394         * the day, but it is very close. This method allows you to use the NOAACalculator and still calculate <em>chatzos
395         * </em> as six <em>shaos zmaniyos</em> after sunrise. There are currently two {@link
396         * com.kosherjava.zmanim.util.AstronomicalCalculator calculators} available in the API, the {@link
397         * com.kosherjava.zmanim.util.NOAACalculator} and the {@link com.kosherjava.zmanim.util.SunTimesCalculator}.
398         * The SunTimesCalculator calculates <em>chatzos</em> as halfway between sunrise and sunset (and of six <em>shaos
399         * zmaniyos</em>), while the NOAACalculator calculates it as astronomical <em>chatzos</em> that is slightly more
400         * accurate. This method allows you to use the NOAACalculator and still calculate <em>chatzos</em> as six <em>shaos
401         * zmaniyos</em> after sunrise. See <a href="https://kosherjava.com/2020/07/02/definition-of-chatzos/">The Definition
402         * of <em>Chatzos</em></a> for a detailed explanation of the ways to calculate <em>Chatzos</em>.
403         *
404         * @see com.kosherjava.zmanim.util.NOAACalculator#getUTCNoon(Calendar, GeoLocation)
405         * @see com.kosherjava.zmanim.util.SunTimesCalculator#getUTCNoon(Calendar, GeoLocation)
406         * @see com.kosherjava.zmanim.util.AstronomicalCalculator#getUTCNoon(Calendar, GeoLocation)
407         * @see AstronomicalCalendar#getSunTransit(Date, Date)
408         * @see #getChatzos()
409         * @see #getSunTransit()
410         * @see #isUseAstronomicalChatzos()
411         * 
412         * @return the <code>Date</code> of the latest <em>chatzos</em>. If the calculation can't be computed such
413         *         as in the Arctic Circle where there is at least one day a year where the sun does not rise, and one where
414         *         it does not set, a <code>null</code> will be returned. See detailed explanation on top of the
415         *         {@link AstronomicalCalendar} documentation.
416         */
417        public Date getChatzosAsHalfDay() {
418                return getSunTransit(getSeaLevelSunrise(), getSeaLevelSunset());
419        }
420
421        /**
422         * A generic method for calculating the latest <em>zman krias shema</em> (time to recite shema in the morning) that is 3 *
423         * <em>shaos zmaniyos</em> (temporal hours) after the start of the day, calculated using the start and end of the day passed
424         * to this method. The time from the start of day to the end of day are divided into 12 <em>shaos zmaniyos</em> (temporal
425         * hours), and the latest <em>zman krias shema</em> is calculated as 3 of those <em>shaos zmaniyos</em> after the beginning of
426         * the day. If {@link #isUseAstronomicalChatzosForOtherZmanim()} is <code>true</code>, the 3 <em>shaos zmaniyos</em> will be
427         * based on 1/6 of the time between sunrise and {@link #getSunTransit() astronomical <em>chatzos</em>}. As an example, passing
428         * {@link #getSunrise() sunrise} and {@link #getSunset() sunset} or {@link #getSeaLevelSunrise() sea level sunrise} and {@link
429         * #getSeaLevelSunset() sea level sunset} to this method (or {@link #getElevationAdjustedSunrise()} and {@link
430         * #getElevationAdjustedSunset()} that is driven off the {@link #isUseElevation()} setting) will return <em>sof zman krias
431         * shema</em> according to the opinion of the <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. In cases
432         * where the start and end dates are not synchronous such as in {@link ComplexZmanimCalendar
433         * #getSofZmanShmaAlos16Point1ToTzaisGeonim7Point083Degrees()} <code>false</code> should be passed to the synchronous parameter
434         * to ensure that {@link #isUseAstronomicalChatzosForOtherZmanim()} will not be used.
435         * 
436         * @param startOfDay
437         *            the start of day for calculating <em>zman krias shema</em>. This can be sunrise or any <em>alos</em> passed
438         *            to this method.
439         * @param endOfDay
440         *            the end of day for calculating <em>zman krias shema</em>. This can be sunset or any <em>tzais</em> passed to
441         *            this method.
442         * @param synchronous
443         *            If the <em>zman</em> has a synchronous start and end of the day. If this is <code>false</code>, using a {@link
444         *            #isUseAstronomicalChatzosForOtherZmanim()} makes no sense and will be ignored even if set to true, since by
445         *            definition <em>chatzos</em> will not be the middle of the day for the <em>zman</em>.
446         * @see #isUseAstronomicalChatzosForOtherZmanim()
447         * @return the <code>Date</code> of the latest <em>zman shema</em> based on the start and end of day times passed to this
448         *         method. If the calculation can't be computed such as in the Arctic Circle where there is at least one day
449         *         a year where the sun does not rise, and one where it does not set, a <code>null</code> will be returned. See
450         *         detailed explanation on top of the {@link AstronomicalCalendar} documentation.
451         */
452        public Date getSofZmanShma(Date startOfDay, Date endOfDay, boolean synchronous) {
453                if (isUseAstronomicalChatzosForOtherZmanim() && synchronous) {
454                        return getHalfDayBasedZman(startOfDay, getChatzos(), 3);
455                } else {
456                        return getShaahZmanisBasedZman(startOfDay, endOfDay, 3);
457                }
458        }
459        
460        /**
461         * A generic method for calculating the latest <em>zman krias shema</em> that calls {@link #getSofZmanShma(Date, Date, boolean)}
462         * passing <code>false</code> to the synchronous parameter since there is no way to know if the start and end of the day are 
463         * synchronous. Passing true when they are not synchronous is too much of a risk. See information on that method for more details.
464         * @param startOfDay
465         *            the start of day for calculating <em>zman krias shema</em>. This can be sunrise or any <em>alos</em> passed
466         *            to this method.
467         * @param endOfDay
468         *            the end of day for calculating <em>zman krias shema</em>. This can be sunset or any <em>tzais</em> passed to
469         *            this method.
470         * @return the <code>Date</code> of the latest <em>zman shema</em> based on the start and end of day times passed to this
471         *         method. If the calculation can't be computed such as in the Arctic Circle where there is at least one day
472         *         a year where the sun does not rise, and one where it does not set, a <code>null</code> will be returned. See
473         *         detailed explanation on top of the {@link AstronomicalCalendar} documentation.
474         * @see #getSofZmanShma(Date, Date, boolean)
475         */
476        public Date getSofZmanShma(Date startOfDay, Date endOfDay) {
477                return getSofZmanShma(startOfDay, endOfDay, false);
478        }
479
480        /**
481         * This method returns the latest <em>zman krias shema</em> (time to recite shema in the morning) that is 3 *
482         * {@link #getShaahZmanisGra() <em>shaos zmaniyos</em>} (solar hours) after {@link #getSunrise() sunrise} or
483         * {@link #getSeaLevelSunrise() sea level sunrise} (depending on the {@link #isUseElevation()} setting), according
484         * to the <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. 
485         *  The day is calculated from {@link #getSeaLevelSunrise() sea level sunrise} to {@link #getSeaLevelSunset() sea level
486         *  sunset} or from {@link #getSunrise() sunrise} to {@link #getSunset() sunset} (depending on the
487         *  {@link #isUseElevation()} setting).
488         * 
489         * @see #getSofZmanShma(Date, Date)
490         * @see #getShaahZmanisGra()
491         * @see #isUseElevation()
492         * @see ComplexZmanimCalendar#getSofZmanShmaBaalHatanya()
493         * @return the <code>Date</code> of the latest <em>zman shema</em> according to the GRA. If the calculation can't be
494         *         computed such as in the Arctic Circle where there is at least one day a year where the sun does not rise,
495         *         and one where it does not set, a <code>null</code> will be returned. See the detailed explanation on top
496         *         of the {@link AstronomicalCalendar} documentation.
497         */
498        public Date getSofZmanShmaGRA() {
499                return getSofZmanShma(getElevationAdjustedSunrise(), getElevationAdjustedSunset(), true);
500        }
501
502        /**
503         * This method returns the latest <em>zman krias shema</em> (time to recite shema in the morning) that is 3 *
504         * {@link #getShaahZmanisMGA() <em>shaos zmaniyos</em>} (solar hours) after {@link #getAlos72()}, according to the
505         * <a href="https://en.wikipedia.org/wiki/Avraham_Gombiner">Magen Avraham (MGA)</a>. The day is calculated
506         * from 72 minutes before {@link #getSeaLevelSunrise() sea level sunrise} to 72 minutes after {@link
507         * #getSeaLevelSunset() sea level sunset} or from 72 minutes before {@link #getSunrise() sunrise} to {@link #getSunset()
508         * sunset} (depending on the {@link #isUseElevation()} setting).
509         * 
510         * @return the <code>Date</code> of the latest <em>zman shema</em>. If the calculation can't be computed such as in
511         *         the Arctic Circle where there is at least one day a year where the sun does not rise, and one where it
512         *         does not set, a <code>null</code> will be returned. See detailed explanation on top of the
513         *         {@link AstronomicalCalendar} documentation.
514         * @see #getSofZmanShma(Date, Date)
515         * @see ComplexZmanimCalendar#getShaahZmanis72Minutes()
516         * @see ComplexZmanimCalendar#getAlos72()
517         * @see ComplexZmanimCalendar#getSofZmanShmaMGA72Minutes() that 
518         */
519        public Date getSofZmanShmaMGA() {
520                return getSofZmanShma(getAlos72(), getTzais72(), true);
521        }
522
523        /**
524         * This method returns the <em>tzais</em> (nightfall) based on the opinion of <em>Rabbeinu Tam</em> that
525         * <em>tzais hakochavim</em> is calculated as 72 minutes after sunset, the time it takes to walk 4 <a href=
526         * "https://en.wikipedia.org/wiki/Biblical_and_Talmudic_units_of_measurement">mil</a> at 18 minutes a mil.
527         * According to the <a href="https://en.wikipedia.org/wiki/Samuel_Loew">Machtzis Hashekel</a> in Orach Chaim
528         * 235:3, the <a href="https://en.wikipedia.org/wiki/Joseph_ben_Meir_Teomim">Pri Megadim</a> in Orach
529         * Chaim 261:2 (see the Biur Halacha) and others (see Hazmanim Bahalacha 17:3 and 17:5) the 72 minutes are standard
530         * clock minutes any time of the year in any location. Depending on the {@link #isUseElevation()} setting, a 72-minute
531         * offset from  either {@link #getSunset() sunset} or {@link #getSeaLevelSunset() sea level sunset} is used.
532         * 
533         * @see ComplexZmanimCalendar#getTzais16Point1Degrees()
534         * @return the <code>Date</code> representing 72 minutes after sunset. If the calculation can't be
535         *         computed such as in the Arctic Circle where there is at least one day a year where the sun does not rise,
536         *         and one where it does not set, a <code>null</code> will be returned See detailed explanation on top of the
537         *         {@link AstronomicalCalendar} documentation.
538         */
539        public Date getTzais72() {
540                return getTimeOffset(getElevationAdjustedSunset(), 72 * MINUTE_MILLIS);
541        }
542
543        /**
544         * A method to return candle lighting time, calculated as {@link #getCandleLightingOffset()} minutes before
545         * {@link #getSeaLevelSunset() sea level sunset}. This will return the time for any day of the week, since it can be
546         * used to calculate candle lighting time for <em>Yom Tov</em> (mid-week holidays) as well. Elevation adjustments
547         * are intentionally not performed by this method, but you can calculate it by passing the elevation adjusted sunset
548         * to {@link #getTimeOffset(Date, long)}.
549         * 
550         * @return candle lighting time. If the calculation can't be computed such as in the Arctic Circle where there is at
551         *         least one day a year where the sun does not rise, and one where it does not set, a <code>null</code> will
552         *         be returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation.
553         * 
554         * @see #getSeaLevelSunset()
555         * @see #getCandleLightingOffset()
556         * @see #setCandleLightingOffset(double)
557         */
558        public Date getCandleLighting() {
559                return getTimeOffset(getSeaLevelSunset(), -getCandleLightingOffset() * MINUTE_MILLIS);
560        }
561
562        /**
563         * A generic method for calculating the latest <em>zman tfilah</em> (time to recite the morning prayers)
564         * that is 4 * <em>shaos zmaniyos</em> (temporal hours) after the start of the day, calculated using the start and
565         * end of the day passed to this method.
566         * The time from the start of day to the end of day are divided into 12 <em>shaos zmaniyos</em> (temporal hours),
567         * and <em>sof zman tfila</em> is calculated as 4 of those <em>shaos zmaniyos</em> after the beginning of the day.
568         * As an example, passing {@link #getSunrise() sunrise} and {@link #getSunset() sunset} or {@link #getSeaLevelSunrise()
569         * sea level sunrise} and {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link #isUseElevation()}
570         * elevation setting) to this method will return <em>zman tfilah</em> according to the opinion of the <a href=
571         * "https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. This method's synchronous parameter indicates if the start
572         * and end of day for the calculation are synchronous, having the same offset. This is typically the case, but some
573         * <em>zmanim</em> calculations are based on a start and end at different offsets from the real start and end of the day,
574         * such as starting the day at <em>alos</em> and an ending it at <em>tzais Geonim</em> or some other variant. If the day
575         * is not synchronous a {@link #getHalfDayBasedZman(Date, Date, double) half-day based calculations} will be bypassed.
576         * It would be illogical to use a half-day based calculation that start/end at <em>chatzos</em> when the two "halves" of
577         * the day are not equal, and the halfway point between them is not at <em>chatzos</em>.
578         * 
579         * @param startOfDay
580         *            the start of day for calculating <em>zman tfilah</em>. This can be sunrise or any <em>alos</em> passed
581         *            to this method.
582         * @param endOfDay
583         *            the end of day for calculating <em>zman tfilah</em>. This can be sunset or any <em>tzais</em> passed
584         *            to this method.
585         * @param synchronous
586         *            If the <em>zman</em> has a synchronous start and end of the day. If this is <code>false</code>, using a {@link
587         *            #isUseAstronomicalChatzosForOtherZmanim()} makes no sense and will be ignored even if set to true, since by
588         *            definition <em>chatzos</em> will not be the middle of the day for the <em>zman</em>.
589         * @return the <code>Date</code> of the latest <em>zman tfilah</em> based on the start and end of day times passed
590         *         to this method. If the calculation can't be computed such as in the Arctic Circle where there is at least
591         *         one day a year where the sun does not rise, and one where it does not set, a <code>null</code> will be
592         *         returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation.
593         */
594        public Date getSofZmanTfila(Date startOfDay, Date endOfDay, boolean synchronous) {
595                if (isUseAstronomicalChatzosForOtherZmanim() && synchronous) {
596                        return getHalfDayBasedZman(startOfDay, getChatzos(), 4);
597                } else {
598                        return getShaahZmanisBasedZman(startOfDay, endOfDay, 4);
599                }
600        }
601        
602        /**
603         * A generic method for calculating the latest <em>zman tfila</em> that calls {@link #getSofZmanTfila(Date, Date, boolean)}
604         * passing <code>false</code> to the synchronous parameter since there is no way to know if the start and end of the day are 
605         * synchronous. Passing true when they are not synchronous is too much of a risk. See information on that method for more details.
606         * @param startOfDay
607         *            the start of day for calculating <em>zman tfilah</em>. This can be sunrise or any <em>alos</em> passed
608         *            to this method.
609         * @param endOfDay
610         *            the end of day for calculating <em>zman tfilah</em>. This can be sunset or any <em>tzais</em> passed to
611         *            this method.
612         * @return the <code>Date</code> of the latest <em>zman tfilah</em> based on the start and end of day times passed to this
613         *         method. If the calculation can't be computed such as in the Arctic Circle where there is at least one day
614         *         a year where the sun does not rise, and one where it does not set, a <code>null</code> will be returned. See
615         *         detailed explanation on top of the {@link AstronomicalCalendar} documentation.
616         * @see #getSofZmanShma(Date, Date, boolean)
617         */
618        public Date getSofZmanTfila(Date startOfDay, Date endOfDay) {
619                return getSofZmanTfila(startOfDay, endOfDay, false);
620        }
621
622        /**
623         * This method returns the latest <em>zman tfila</em> (time to recite shema in the morning) that is 4 *
624         * {@link #getShaahZmanisGra() <em>shaos zmaniyos</em> }(solar hours) after {@link #getSunrise() sunrise} or
625         * {@link #getSeaLevelSunrise() sea level sunrise} (depending on the {@link #isUseElevation()} setting), according
626         * to the <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. 
627         * The day is calculated from {@link #getSeaLevelSunrise() sea level sunrise} to {@link #getSeaLevelSunset() sea level
628         * sunset} or from {@link #getSunrise() sunrise} to {@link #getSunset() sunset} (depending on the
629         * {@link #isUseElevation()} setting).
630         * 
631         * @see #getSofZmanTfila(Date, Date)
632         * @see #getShaahZmanisGra()
633         * @see ComplexZmanimCalendar#getSofZmanTfilaBaalHatanya()
634         * @return the <code>Date</code> of the latest <em>zman tfilah</em>. If the calculation can't be computed such as in
635         *         the Arctic Circle where there is at least one day a year where the sun does not rise, and one where it
636         *         does not set, a <code>null</code> will be returned. See detailed explanation on top of the
637         *         {@link AstronomicalCalendar} documentation.
638         */
639        public Date getSofZmanTfilaGRA() {
640                return getSofZmanTfila(getElevationAdjustedSunrise(), getElevationAdjustedSunset(), true);
641        }
642
643        /**
644         * This method returns the latest <em>zman tfila</em> (time to recite shema in the morning) that is 4 *
645         * {@link #getShaahZmanisMGA() <em>shaos zmaniyos</em>} (solar hours) after {@link #getAlos72()}, according to the
646         * <em><a href="https://en.wikipedia.org/wiki/Avraham_Gombiner">Magen Avraham (MGA)</a></em>. The day is calculated
647         * from 72 minutes before {@link #getSeaLevelSunrise() sea level sunrise} to 72 minutes after {@link
648         * #getSeaLevelSunset() sea level sunset} or from 72 minutes before {@link #getSunrise() sunrise} to {@link #getSunset()
649         * sunset} (depending on the {@link #isUseElevation()} setting).
650         * 
651         * @return the <code>Date</code> of the latest <em>zman tfila</em>. If the calculation can't be computed such as in
652         *         the Arctic Circle where there is at least one day a year where the sun does not rise, and one where it
653         *         does not set, a <code>null</code> will be returned. See detailed explanation on top of the
654         *         {@link AstronomicalCalendar} documentation.
655         * @see #getSofZmanTfila(Date, Date)
656         * @see #getShaahZmanisMGA()
657         * @see #getAlos72()
658         */
659        public Date getSofZmanTfilaMGA() {
660                return getSofZmanTfila(getAlos72(), getTzais72(), true);
661        }
662
663        /**
664         * A generic method for calculating <em>mincha gedola</em> (the earliest time to recite the <em>mincha</em> prayers) that
665         * is 6.5 * <em>shaos zmaniyos</em> (temporal hours) after the start of the day, calculated using the start and end of the
666         * day passed to this method. The time from the start of day to the end of day are divided into 12 <em>shaos zmaniyos</em>
667         * (temporal hours), and <em>mincha gedola</em> is calculated as 6.5 of those <em>shaos zmaniyos</em> after the beginning
668         * of the day. As an example, passing {@link #getSunrise() sunrise} and {@link #getSunset() sunset} or {@link
669         * #getSeaLevelSunrise() sea level sunrise} and {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link
670         * #isUseElevation()} elevation setting) to this method will return <em>mincha gedola</em> according to the opinion of the
671         * <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. Alternatively, this method uses {@link
672         * #isUseAstronomicalChatzosForOtherZmanim()} to control if the time is based on 6.5 <em>shaos zmaniyos</em> into the day
673         * mentioned above, or as half an hour <em>zmaniyos</em> based on the second half of the day after <em>chatzos</em> ({@link
674         * #getSunTransit() astronomical <em>chatzos</em>} if supported by the {@link AstronomicalCalculator calculator} and {@link
675         * #isUseAstronomicalChatzos() configured} or {@link #getChatzosAsHalfDay() <em>chatzos</em> as half a day} if not. This
676         * method's synchronous parameter indicates if the start and end of day for the calculation are synchronous, having the same
677         * offset. This is typically the case, but some <em>zmanim</em> calculations are based on a start and end at different offsets
678         * from the real start and end of the day, such as starting the day at <em>alos</em> and an ending it at <em>tzais Geonim</em>
679         * or some other variant. If the day is not synchronous a {@link #getHalfDayBasedZman(Date, Date, double) half-day based
680         * calculations} will be bypassed. It would be illogical to use a half-day based calculation that start/end at <em>chatzos</em>
681         * when the two "halves" of the day are not equal, and the halfway point between them is not at <em>chatzos</em>.
682         * 
683         * @param startOfDay
684         *            the start of day for calculating <em>Mincha gedola</em>. This can be sunrise or any <em>alos</em> passed
685         *            to this method.
686         * @param endOfDay
687         *            the end of day for calculating <em>Mincha gedola</em>. This can be sunset or any <em>tzais</em> passed
688         *            to this method.
689         * @param synchronous
690         *            If the <em>zman</em> has a synchronous start and end of the day. If this is <code>false</code>, using a {@link
691         *            #isUseAstronomicalChatzosForOtherZmanim()} makes no sense and will be ignored even if set to true, since by
692         *            definition <em>chatzos</em> will not be the middle of the day for the <em>zman</em>.
693         * @return the <code>Date</code> of the time of <em>Mincha gedola</em> based on the start and end of day times
694         *         passed to this method. If the calculation can't be computed such as in the Arctic Circle where there is
695         *         at least one day a year where the sun does not rise, and one where it does not set, a <code>null</code> will
696         *         be returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation.
697         * @see #getSunTransit()
698         * @see #getChatzosAsHalfDay()
699         * @see #getChatzos()
700         * @see #isUseAstronomicalChatzos()
701         * @see #isUseAstronomicalChatzosForOtherZmanim()
702         */
703        public Date getMinchaGedola(Date startOfDay, Date endOfDay, boolean synchronous) {
704                if (isUseAstronomicalChatzosForOtherZmanim() && synchronous) {
705                        return getHalfDayBasedZman(getChatzos(), endOfDay, 0.5);
706                } else {
707                        return getShaahZmanisBasedZman(startOfDay, endOfDay, 6.5);
708                }
709        }
710        
711        /**
712         * A generic method for calculating <em>mincha gedola</em> that calls {@link #getMinchaGedola(Date, Date, boolean)} passing
713         * <code>false</code> to the synchronous parameter since there is no way to know if the start and end of the day are
714         * synchronous. Passing true when they are not synchronous is too much of a risk. See information on that method for more
715         * details.
716         * @param startOfDay
717         *            the start of day for calculating <em>Mincha gedola</em>. This can be sunrise or any <em>alos</em> passed
718         *            to this method.
719         * @param endOfDay
720         *            the end of day for calculating <em>Mincha gedola</em>. This can be sunset or any <em>tzais</em> passed to
721         *            this method.
722         * @return the <code>Date</code> of the latest <em>Mincha gedola</em> based on the start and end of day times passed to this
723         *         method. If the calculation can't be computed such as in the Arctic Circle where there is at least one day
724         *         a year where the sun does not rise, and one where it does not set, a <code>null</code> will be returned. See
725         *         detailed explanation on top of the {@link AstronomicalCalendar} documentation.
726         * @see #getMinchaGedola(Date, Date, boolean)
727         */
728        public Date getMinchaGedola(Date startOfDay, Date endOfDay) {
729                return getMinchaGedola(startOfDay, endOfDay, false);
730        }
731
732        /**
733         * This method returns the latest <em>mincha gedola</em>,the earliest time one can pray <em>mincha</em> that is 6.5 *
734         * {@link #getShaahZmanisGra() <em>shaos zmaniyos</em>} (solar hours) after {@link #getSunrise() sunrise} or
735         * {@link #getSeaLevelSunrise() sea level sunrise} (depending on the {@link #isUseElevation()} setting), according
736         * to the <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. <em>Mincha gedola</em> is the earliest
737         * time one can pray <em>mincha</em>. The Ramba"m is of the opinion that it is better to delay <em>mincha</em> until
738         * {@link #getMinchaKetana() <em>mincha ketana</em>} while the Ra"sh, Tur, GRA and others are of the
739         * opinion that <em>mincha</em> can be prayed <em>lechatchila</em> starting at <em>mincha gedola</em>.
740         * The day is calculated from {@link #getSeaLevelSunrise() sea level sunrise} to {@link #getSeaLevelSunset() sea level
741         * sunset} or {@link #getSunrise() sunrise} to {@link #getSunset() sunset} (depending on the {@link #isUseElevation()}
742         * setting).
743         * @todo Consider adjusting this to calculate the time as half an hour <em>zmaniyos</em> after either {@link
744         *         #getSunTransit() astronomical <em>chatzos</em>} or {@link #getChatzosAsHalfDay() <em>chatzos</em> as half a day}
745         *         for {@link AstronomicalCalculator calculators} that support it, based on {@link #isUseAstronomicalChatzos()}.
746         * 
747         * @see #getMinchaGedola(Date, Date)
748         * @see #getShaahZmanisGra()
749         * @see #getMinchaKetana()
750         * @see ComplexZmanimCalendar#getMinchaGedolaBaalHatanya()
751         * @return the <code>Date</code> of the time of mincha gedola. If the calculation can't be computed such as in the
752         *         Arctic Circle where there is at least one day a year where the sun does not rise, and one where it does
753         *         not set, a <code>null</code> will be returned. See detailed explanation on top of the
754         *         {@link AstronomicalCalendar} documentation.
755         */
756        public Date getMinchaGedola() {
757                return getMinchaGedola(getElevationAdjustedSunrise(), getElevationAdjustedSunset(), true);
758        }
759        
760        /**
761         * A generic method for calculating <em>samuch lemincha ketana</em>, / near <em>mincha ketana</em> time that is half
762         * an hour before {@link #getMinchaKetana(Date, Date)}  or 9 * <em>shaos zmaniyos</em> (temporal hours) after the
763         * start of the day, calculated using the start and end of the day passed to this method.
764         * The time from the start of day to the end of day are divided into 12 <em>shaos zmaniyos</em> (temporal hours), and
765         * <em>samuch lemincha ketana</em> is calculated as 9 of those <em>shaos zmaniyos</em> after the beginning of the day.
766         * For example, passing {@link #getSunrise() sunrise} and {@link #getSunset() sunset} or {@link #getSeaLevelSunrise() sea
767         * level sunrise} and {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link #isUseElevation()} elevation
768         * setting) to this method will return <em>samuch lemincha ketana</em> according to the opinion of the
769         * <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. See the <a href=
770         * "https://hebrewbooks.org/pdfpager.aspx?req=60387&st=&pgnum=294">Mechaber and Mishna Berurah 232</a> and <a href=
771         * "https://hebrewbooks.org/pdfpager.aspx?req=60388&pgnum=34">249:2</a>.
772         * 
773         * @param startOfDay
774         *            the start of day for calculating <em>samuch lemincha ketana</em>. This can be sunrise or any <em>alos</em>
775         *            passed to this method.
776         * @param endOfDay
777         *            the end of day for calculating <em>samuch lemincha ketana</em>. This can be sunset or any <em>tzais</em>
778         *            passed to this method.
779         * @param synchronous
780         *            If the <em>zman</em> has a synchronous start and end of the day. If this is <code>false</code>, using a {@link
781         *            #isUseAstronomicalChatzosForOtherZmanim()} makes no sense and will be ignored even if set to true, since by
782         *            definition <em>chatzos</em> will not be the middle of the day for the <em>zman</em>.
783         * @return the <code>Date</code> of the time of <em>Mincha ketana</em> based on the start and end of day times
784         *         passed to this method. If the calculation can't be computed such as in the Arctic Circle where there is
785         *         at least one day a year where the sun does not rise, and one where it does not set, a <code>null</code> will
786         *         be returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation.
787         *
788         * @see ComplexZmanimCalendar#getSamuchLeMinchaKetanaGRA()
789         * @see ComplexZmanimCalendar#getSamuchLeMinchaKetana16Point1Degrees()
790         * @see ComplexZmanimCalendar#getSamuchLeMinchaKetana72Minutes()
791         */
792        public Date getSamuchLeMinchaKetana(Date startOfDay, Date endOfDay, boolean synchronous) {
793                if (isUseAstronomicalChatzosForOtherZmanim() && synchronous) {
794                        return getHalfDayBasedZman(getChatzos(), endOfDay, 3);
795                } else {
796                        return getShaahZmanisBasedZman(startOfDay, endOfDay, 9);
797                }
798        }
799        
800        /**
801         * A generic method for calculating <em>samuch lemincha ketana</em> that calls {@link #getSamuchLeMinchaKetana(Date, Date, boolean)}
802         * passing <code>false</code> to the synchronous parameter since there is no way to know if the start and end of the day are 
803         * synchronous. Passing true when they are not synchronous is too much of a risk. See information on that method for more details.
804         * @param startOfDay
805         *            the start of day for calculating <em>samuch lemincha ketana</em>. This can be sunrise or any <em>alos</em>
806         *            passed to this method.
807         * @param endOfDay
808         *            the end of day for calculating <em>samuch lemincha ketana</em>. This can be sunset or any <em>tzais</em>
809         *            passed to this method.
810         * @return the <code>Date</code> of the time of <em>samuch lemincha ketana</em> based on the start and end of day times
811         *         passed to this method. If the calculation can't be computed such as in the Arctic Circle where there is
812         *         at least one day a year where the sun does not rise, and one where it does not set, a <code>null</code> will
813         *         be returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation.
814         * @see #getSamuchLeMinchaKetana(Date, Date, boolean)
815         */
816        public Date getSamuchLeMinchaKetana(Date startOfDay, Date endOfDay) {
817                return getSamuchLeMinchaKetana(startOfDay, endOfDay, false);
818        }
819
820        /**
821         * A generic method for calculating <em>mincha ketana</em>, (the preferred time to recite the mincha prayers in
822         * the opinion of the <em><a href="https://en.wikipedia.org/wiki/Maimonides">Rambam</a></em> and others) that is
823         * 9.5 * <em>shaos zmaniyos</em> (temporal hours) after the start of the day, calculated using the start and end
824         * of the day passed to this method.
825         * The time from the start of day to the end of day are divided into 12 <em>shaos zmaniyos</em> (temporal hours), and
826         * <em>mincha ketana</em> is calculated as 9.5 of those <em>shaos zmaniyos</em> after the beginning of the day. As an
827         * example, passing {@link #getSunrise() sunrise} and {@link #getSunset() sunset} or {@link #getSeaLevelSunrise() sea
828         * level sunrise} and {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link #isUseElevation()}
829         * elevation setting) to this method will return <em>mincha ketana</em> according to the opinion of the
830         * <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. This method's synchronous parameter indicates if the start
831         * and end of day for the calculation are synchronous, having the same offset. This is typically the case, but some
832         * <em>zmanim</em> calculations are based on a start and end at different offsets from the real start and end of the day,
833         * such as starting the day at <em>alos</em> and an ending it at <em>tzais Geonim</em> or some other variant. If the day
834         * is not synchronous a {@link #getHalfDayBasedZman(Date, Date, double) half-day based calculations} will be bypassed.
835         * It would be illogical to use a half-day based calculation that start/end at <em>chatzos</em> when the two "halves" of
836         * the day are not equal, and the halfway point between them is not at <em>chatzos</em>.
837         * 
838         * @param startOfDay
839         *            the start of day for calculating <em>Mincha ketana</em>. This can be sunrise or any <em>alos</em> passed
840         *            to this method.
841         * @param endOfDay
842         *            the end of day for calculating <em>Mincha ketana</em>. This can be sunset or any <em>tzais</em> passed to
843         *            this method.
844         * @param synchronous
845         *            If the <em>zman</em> has a synchronous start and end of the day. If this is <code>false</code>, using a {@link
846         *            #isUseAstronomicalChatzosForOtherZmanim()} makes no sense and will be ignored even if set to true, since by
847         *            definition <em>chatzos</em> will not be the middle of the day for the <em>zman</em>.
848         * @return the <code>Date</code> of the time of <em>Mincha ketana</em> based on the start and end of day times
849         *         passed to this method. If the calculation can't be computed such as in the Arctic Circle where there is
850         *         at least one day a year where the sun does not rise, and one where it does not set, a <code>null</code> will
851         *         be returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation.
852         */
853        public Date getMinchaKetana(Date startOfDay, Date endOfDay, boolean synchronous) {
854                if (isUseAstronomicalChatzosForOtherZmanim() && synchronous) {
855                        return getHalfDayBasedZman(getChatzos(), endOfDay, 3.5);
856                } else {
857                        return getShaahZmanisBasedZman(startOfDay, endOfDay, 9.5);
858                }
859        }
860        
861        /**
862         * A generic method for calculating <em>mincha ketana</em> that calls {@link #getMinchaKetana(Date, Date, boolean)} passing
863         * <code>false</code> to the synchronous parameter since there is no way to know if the start and end of the day are synchronous.
864         * Passing true when they are not synchronous is too much of a risk. See information on that method for more details.
865         * @param startOfDay
866         *            the start of day for calculating <em>Mincha ketana</em>. This can be sunrise or any <em>alos</em> passed
867         *            to this method.
868         * @param endOfDay
869         *            the end of day for calculating <em>Mincha ketana</em>. This can be sunset or any <em>tzais</em> passed to
870         *            this method.
871         * @return the <code>Date</code> of the time of <em>Mincha ketana</em> based on the start and end of day times
872         *         passed to this method. If the calculation can't be computed such as in the Arctic Circle where there is
873         *         at least one day a year where the sun does not rise, and one where it does not set, a <code>null</code> will
874         *         be returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation.
875         * @see #getMinchaKetana(Date, Date, boolean)
876         */
877        public Date getMinchaKetana(Date startOfDay, Date endOfDay) {
878                return getMinchaKetana(startOfDay, endOfDay, false);
879        }
880
881        /**
882         * This method returns <em>mincha ketana</em>,the preferred earliest time to pray <em>mincha</em> in the
883         * opinion of the <em><a href="https://en.wikipedia.org/wiki/Maimonides">Rambam</a></em> and others, that is 9.5
884         * * {@link #getShaahZmanisGra() <em>shaos zmaniyos</em>} (solar hours) after {@link #getSunrise() sunrise} or
885         * {@link #getSeaLevelSunrise() sea level sunrise} (depending on the {@link #isUseElevation()} setting), according
886         * to the <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. For more information on this see the
887         * documentation on {@link #getMinchaGedola() <em>mincha gedola</em>}.
888         * The day is calculated from {@link #getSeaLevelSunrise() sea level sunrise} to {@link #getSeaLevelSunset() sea level
889         * sunset} or from {@link #getSunrise() sunrise} to {@link #getSunset() sunset} (depending on the {@link #isUseElevation()}
890         * setting.
891         * 
892         * @see #getMinchaKetana(Date, Date)
893         * @see #getShaahZmanisGra()
894         * @see #getMinchaGedola()
895         * @see ComplexZmanimCalendar#getMinchaKetanaBaalHatanya()
896         * @return the <code>Date</code> of the time of mincha ketana. If the calculation can't be computed such as in the
897         *         Arctic Circle where there is at least one day a year where the sun does not rise, and one where it does
898         *         not set, a <code>null</code> will be returned. See detailed explanation on top of the
899         *         {@link AstronomicalCalendar} documentation.
900         */
901        public Date getMinchaKetana() {
902                return getMinchaKetana(getElevationAdjustedSunrise(), getElevationAdjustedSunset(), true);
903        }
904
905        /**
906         * A generic method for calculating <em>plag hamincha</em> (the earliest time that Shabbos can be started) that is
907         * 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
908         * the day passed to the method.
909         * The time from the start of day to the end of day are divided into 12 <em>shaos zmaniyos</em> (temporal hours), and
910         * <em>plag hamincha</em> is calculated as 10.75 of those <em>shaos zmaniyos</em> after the beginning of the day. As an
911         * example, passing {@link #getSunrise() sunrise} and {@link #getSunset() sunset} or {@link #getSeaLevelSunrise() sea level
912         * sunrise} and {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link #isUseElevation()} elevation
913         * setting) to this method will return <em>plag mincha</em> according to the opinion of the
914         * <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. This method's synchronous parameter indicates if the start
915         * and end of day for the calculation are synchronous, having the same offset. This is typically the case, but some
916         * <em>zmanim</em> calculations are based on a start and end at different offsets from the real start and end of the day,
917         * such as starting the day at <em>alos</em> and an ending it at <em>tzais Geonim</em> or some other variant. If the day
918         * is not synchronous a {@link #getHalfDayBasedZman(Date, Date, double) half-day based calculations} will be bypassed. It
919         * would be illogical to use a half-day based calculation that start/end at <em>chatzos</em> when the two "halves" of the
920         * day are not equal, and the halfway point between them is not at <em>chatzos</em>.
921         * 
922         * @param startOfDay
923         *            the start of day for calculating <em>plag hamincha</em>. This can be sunrise or any <em>alos</em> passed to
924         *            this method.
925         * @param endOfDay
926         *            the end of day for calculating <em>plag hamincha</em>. This can be sunset or any <em>tzais</em> passed to
927         *            this method.
928         * @param synchronous
929         *            If the <em>zman</em> has a synchronous start and end of the day. If this is <code>false</code>, using a {@link
930         *            #isUseAstronomicalChatzosForOtherZmanim()} makes no sense and will be ignored even if set to true, since by
931         *            definition <em>chatzos</em> will not be the middle of the day for the <em>zman</em>.
932         * @return the <code>Date</code> of the time of <em>plag hamincha</em> based on the start and end of day times
933         *         passed to this method. If the calculation can't be computed such as in the Arctic Circle where there is
934         *         at least one day a year where the sun does not rise, and one where it does not set, a <code>null</code>
935         *         will be returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation.
936         */
937        public Date getPlagHamincha(Date startOfDay, Date endOfDay, boolean synchronous) {
938                if (isUseAstronomicalChatzosForOtherZmanim() && synchronous) {
939                        return getHalfDayBasedZman(getChatzos(), endOfDay, 4.75);
940                } else {
941                        return getShaahZmanisBasedZman(startOfDay, endOfDay, 10.75);
942                }
943        }
944        
945        /**
946         * A generic method for calculating <em>plag hamincha</em> that calls {@link #getPlagHamincha(Date, Date, boolean)} passing
947         * <code>false</code> to the synchronous parameter since there is no way to know if the start and end of the day are synchronous.
948         * Passing true when they are not synchronous is too much of a risk. See information on that method for more details.
949         * @param startOfDay
950         *            the start of day for calculating <em>plag hamincha</em>. This can be sunrise or any <em>alos</em> passed to this method.
951         * @param endOfDay
952         *            the end of day for calculating <em>plag hamincha</em>. This can be sunset or any <em>tzais</em> passed to this method.
953         * @return the <code>Date</code> of the time of <em>plag hamincha</em> based on the start and end of day times
954         *         passed to this method. If the calculation can't be computed such as in the Arctic Circle where there is
955         *         at least one day a year where the sun does not rise, and one where it does not set, a <code>null</code>
956         *         will be returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation.
957         * @see #getPlagHamincha(Date, Date, boolean)
958         */
959        public Date getPlagHamincha(Date startOfDay, Date endOfDay) {
960                return getPlagHamincha(startOfDay, endOfDay, false);
961        }
962
963        /**
964         * This method returns <em>plag hamincha</em>, that is 10.75 * {@link #getShaahZmanisGra() <em>shaos zmaniyos</em>}
965         * (solar hours) after {@link #getSunrise() sunrise} or {@link #getSeaLevelSunrise() sea level sunrise} (depending on
966         * the {@link #isUseElevation()} setting), according to the <a href="https://en.wikipedia.org/wiki/Vilna_Gaon"
967         * >GRA</a>. <em>Plag hamincha</em> is the earliest time that <em>Shabbos</em> can be started.
968         * The day is calculated from {@link #getSeaLevelSunrise() sea level sunrise} to {@link #getSeaLevelSunset() sea level
969         * sunset} or {@link #getSunrise() sunrise} to {@link #getSunset() sunset} (depending on the {@link #isUseElevation()}
970         * 
971         * @see #getPlagHamincha(Date, Date, boolean)
972         * @see #getPlagHamincha(Date, Date)
973         * @see ComplexZmanimCalendar#getPlagHaminchaBaalHatanya()
974         * @return the <code>Date</code> of the time of <em>plag hamincha</em>. If the calculation can't be computed such as
975         *         in the Arctic Circle where there is at least one day a year where the sun does not rise, and one where it
976         *         does not set, a <code>null</code> will be returned. See detailed explanation on top of the
977         *         {@link AstronomicalCalendar} documentation.
978         */
979        public Date getPlagHamincha() {
980                return getPlagHamincha(getElevationAdjustedSunrise(), getElevationAdjustedSunset(), true);
981        }
982
983        /**
984         * A method that returns a <em>shaah zmanis</em> ({@link #getTemporalHour(Date, Date) temporal hour}) according to
985         * the opinion of the <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. This calculation divides the day
986         * based on the opinion of the <em>GRA</em> that the day runs from from {@link #getSeaLevelSunrise() sea level
987         * sunrise} to {@link #getSeaLevelSunset() sea level sunset} or {@link #getSunrise() sunrise} to {@link #getSunset()
988         * sunset} (depending on the {@link #isUseElevation()} setting). The day is split into 12 equal parts with each one
989         * being a <em>shaah zmanis</em>. This method is similar to {@link #getTemporalHour()}, but can account for elevation.
990         * 
991         * @return the <code>long</code> millisecond length of a <em>shaah zmanis</em> calculated from sunrise to sunset.
992         *         If the calculation can't be computed such as in the Arctic Circle where there is at least one day a year
993         *         where the sun does not rise, and one where it does not set, {@link Long#MIN_VALUE} will be returned. See
994         *         detailed explanation on top of the {@link AstronomicalCalendar} documentation.
995         * @see #getTemporalHour(Date, Date)
996         * @see #getSeaLevelSunrise()
997         * @see #getSeaLevelSunset()
998         * @see ComplexZmanimCalendar#getShaahZmanisBaalHatanya()
999         */
1000        public long getShaahZmanisGra() {
1001                return getTemporalHour(getElevationAdjustedSunrise(), getElevationAdjustedSunset());
1002        }
1003
1004        /**
1005         * A method that returns a <em>shaah zmanis</em> (temporal hour) according to the opinion of the <em><a href=
1006         * "https://en.wikipedia.org/wiki/Avraham_Gombiner">Magen Avraham (MGA)</a></em> based on a 72-minute <em>alos</em>
1007         * and <em>tzais</em>. This calculation divides the day that runs from dawn to dusk (for <em>sof zman krias shema</em> and
1008         * <em>tfila</em>). Dawn for this calculation is 72 minutes before {@link #getSunrise() sunrise} or {@link #getSeaLevelSunrise()
1009         * sea level sunrise} (depending on the {@link #isUseElevation()} elevation setting) and dusk is 72 minutes after {@link
1010         * #getSunset() sunset} or {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link #isUseElevation()} elevation
1011         * setting). This day is split into 12 equal parts with each part being a <em>shaah zmanis</em>. Alternate methods of calculating
1012         * a <em>shaah zmanis</em> according to the Magen Avraham (MGA) are available in the subclass {@link ComplexZmanimCalendar}.
1013         * 
1014         * @return the <code>long</code> millisecond length of a <em>shaah zmanis</em>. If the calculation can't be computed
1015         *         such as in the Arctic Circle where there is at least one day a year where the sun does not rise, and one
1016         *         where it does not set, {@link Long#MIN_VALUE} will be returned. See detailed explanation on top of the
1017         *         {@link AstronomicalCalendar} documentation.
1018         */
1019        public long getShaahZmanisMGA() {
1020                return getTemporalHour(getAlos72(), getTzais72());
1021        }
1022
1023        /**
1024         * Default constructor will set a default {@link GeoLocation#GeoLocation()}, a default
1025         * {@link AstronomicalCalculator#getDefault() AstronomicalCalculator} and default the calendar to the current date.
1026         * 
1027         * @see AstronomicalCalendar#AstronomicalCalendar()
1028         */
1029        public ZmanimCalendar() {
1030                super();
1031        }
1032
1033        /**
1034         * A constructor that takes a {@link GeoLocation} as a parameter.
1035         * 
1036         * @param location
1037         *            the location
1038         */
1039        public ZmanimCalendar(GeoLocation location) {
1040                super(location);
1041        }
1042
1043        /**
1044         * A method to get the offset in minutes before {@link AstronomicalCalendar#getSeaLevelSunset() sea level sunset} which
1045         * is used in calculating candle lighting time. The default time used is 18 minutes before sea level sunset. Some
1046         * calendars use 15 minutes, while the custom in Jerusalem is to use a 40-minute offset. Please check the local custom
1047         * for candle lighting time.
1048         * 
1049         * @return Returns the currently set candle lighting offset in minutes.
1050         * @see #getCandleLighting()
1051         * @see #setCandleLightingOffset(double)
1052         */
1053        public double getCandleLightingOffset() {
1054                return candleLightingOffset;
1055        }
1056
1057        /**
1058         * A method to set the offset in minutes before {@link AstronomicalCalendar#getSeaLevelSunset() sea level sunset} that is
1059         * used in calculating candle lighting time. The default time used is 18 minutes before sunset. Some calendars use 15
1060         * minutes, while the custom in Jerusalem is to use a 40-minute offset.
1061         * 
1062         * @param candleLightingOffset
1063         *            The candle lighting offset to set in minutes.
1064         * @see #getCandleLighting()
1065         * @see #getCandleLightingOffset()
1066         */
1067        public void setCandleLightingOffset(double candleLightingOffset) {
1068                this.candleLightingOffset = candleLightingOffset;
1069        }
1070        
1071        /**
1072         * This is a utility method to determine if the current Date (date-time) passed in has a <em>melacha</em> (work) prohibition.
1073         * 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
1074         * class. Sunset is the classes current day's {@link #getElevationAdjustedSunset() elevation adjusted sunset} that observes the
1075         * {@link #isUseElevation()} settings. The {@link JewishCalendar#getInIsrael()} will be set by the inIsrael parameter.
1076         * 
1077         * @param currentTime the current time
1078         * @param tzais the time of tzais
1079         * @param inIsrael whether to use Israel holiday scheme or not
1080         * 
1081         * @return true if <em>melacha</em> is prohibited or false if it is not.
1082         * 
1083         * @see JewishCalendar#isAssurBemelacha()
1084         * @see JewishCalendar#hasCandleLighting()
1085         * @see JewishCalendar#setInIsrael(boolean)
1086         */
1087        public boolean isAssurBemlacha(Date currentTime, Date tzais, boolean inIsrael) {
1088                JewishCalendar jewishCalendar = new JewishCalendar();
1089                jewishCalendar.setGregorianDate(getCalendar().get(Calendar.YEAR), getCalendar().get(Calendar.MONTH),
1090                                getCalendar().get(Calendar.DAY_OF_MONTH));
1091                jewishCalendar.setInIsrael(inIsrael);
1092                
1093                if (jewishCalendar.hasCandleLighting() && currentTime.compareTo(getElevationAdjustedSunset()) >= 0) { //erev shabbos, YT or YT sheni and after shkiah
1094                        return true;
1095                }
1096                
1097                //is shabbos or YT and it is before tzais
1098                return jewishCalendar.isAssurBemelacha() && currentTime.compareTo(tzais) <= 0;
1099        }
1100
1101        /**
1102         * A generic utility method for calculating any <em>shaah zmanis</em> (temporal hour) based <em>zman</em> with the
1103         * day defined as the start and end of day (or night) and the number of <em>shaos zmaniyos</em> passed to the
1104         * method. This simplifies the code in other methods such as {@link #getPlagHamincha(Date, Date)} and cuts down on
1105         * code replication. As an example, passing {@link #getSunrise() sunrise} and {@link #getSunset() sunset} or {@link
1106         * #getSeaLevelSunrise() sea level sunrise} and {@link #getSeaLevelSunset() sea level sunset} (depending on the
1107         * {@link #isUseElevation()} elevation setting) and 10.75 hours to this method will return <em>plag mincha</em>
1108         * according to the opinion of the <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>.
1109         * 
1110         * @param startOfDay
1111         *            the start of day for calculating the <em>zman</em>. This can be sunrise or any <em>alos</em> passed
1112         *            to this method.
1113         * @param endOfDay
1114         *            the end of day for calculating the <em>zman</em>. This can be sunset or any <em>tzais</em> passed to
1115         *            this method.
1116         * @param hours
1117         *            the number of <em>shaos zmaniyos</em> (temporal hours) to offset from the start of day
1118         * @return the <code>Date</code> of the time of <em>zman</em> with the <em>shaos zmaniyos</em> (temporal hours)
1119         *         in the day offset from the start of day passed to this method. If the calculation can't be computed such
1120         *         as in the Arctic Circle where there is at least one day a year where the sun does not rise, and one
1121         *         where it does not set, a <code>null</code> will be  returned. See detailed explanation on top of the
1122         *         {@link AstronomicalCalendar} documentation.
1123         */
1124        public Date getShaahZmanisBasedZman(Date startOfDay, Date endOfDay, double hours) {
1125                long shaahZmanis = getTemporalHour(startOfDay, endOfDay);
1126                return getTimeOffset(startOfDay, shaahZmanis * hours);
1127        }
1128        
1129        /**
1130         * A utility method that returns the percentage of a <em>shaah zmanis</em> after sunset (or before sunrise) for a given degree
1131         * offset. For the <a href="https://kosherjava.com/2022/01/12/equinox-vs-equilux-zmanim-calculations/">equilux</a> where there
1132         * 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
1133         * or date, but will typically only be of interest at the equinox/equilux to calculate the percentage of a <em>shaah zmanis</em>
1134         * 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
1135         * and the <a href="https://en.wikipedia.org/wiki/Hezekiah_da_Silva">Pri Chadash</a> who calculate <em>tzais</em> as a percentage
1136         * 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
1137         * on the equinox / equilux in Israel), this method allows calculations for any degree level for any location.
1138         * 
1139         * @param degrees
1140         *            the number of degrees below the horizon after sunset.
1141         * @param sunset
1142         *            if <code>true</code> the calculation should be degrees after sunset, or if <code>false</code>, degrees before sunrise.
1143         * @return the <code>double</code> percentage of a <em>sha'ah zmanis</em> for a given set of degrees below the astronomical horizon
1144         *         for the current calendar.  If the calculation can't be computed a {@link Double#MIN_VALUE} will be returned. See detailed
1145         *         explanation on top of the page.
1146         */
1147        public double getPercentOfShaahZmanisFromDegrees(double degrees, boolean sunset) {
1148                Date seaLevelSunrise = getSeaLevelSunrise();
1149                Date seaLevelSunset = getSeaLevelSunset();
1150                Date twilight = null;
1151                if (sunset) {
1152                        twilight = getSunsetOffsetByDegrees(GEOMETRIC_ZENITH + degrees);
1153                } else {
1154                        twilight = getSunriseOffsetByDegrees(GEOMETRIC_ZENITH + degrees);
1155                }
1156                if (seaLevelSunrise == null || seaLevelSunset == null || twilight == null) {
1157                        return Double.MIN_VALUE;
1158                }
1159                double shaahZmanis = (seaLevelSunset.getTime() - seaLevelSunrise.getTime()) / 12.0;
1160                long riseSetToTwilight;
1161                if (sunset) {
1162                        riseSetToTwilight = twilight.getTime() - seaLevelSunset.getTime();
1163                } else {
1164                        riseSetToTwilight = seaLevelSunrise.getTime() - twilight.getTime();
1165                }
1166                return riseSetToTwilight / shaahZmanis;
1167        }
1168        
1169        /**
1170         * A utility method to calculate <em>zmanim</em> based on <a href="https://en.wikipedia.org/wiki/Moshe_Feinstein">Rav Moshe
1171         * Feinstein</a> and others as calculated in <a href="https://en.wikipedia.org/wiki/Mesivtha_Tifereth_Jerusalem">MTJ</a>, <a href=
1172         * "https://en.wikipedia.org/wiki/Mesivtha_Tifereth_Jerusalem">Yeshiva of Staten Island</a>, and Camp Yeshiva
1173         * of Staten Island and other calendars. The day is split in two, from <em>alos</em> / sunrise to <em>chatzos</em>, and the
1174         * second half of the day, from <em>chatzos</em> to sunset / <em>tzais</em>. Morning based times are calculated. based on the first
1175         * 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
1176         * <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>
1177         * based on the second half of the day. Some <em>zmanim</em> calculations can be based on subtracting <em>shaos zmaniyos</em>
1178         * from the end of the day, and that is supported by passing a negative hour to this method.
1179         * 
1180         * @param startOfHalfDay
1181         *            The start of the half day. This would be <em>alos</em> or sunrise for morning based times such as <em>sof zman krias
1182         *            shema</em> and <em>chatzos</em> for afternoon based times such as <em>mincha gedola</em>.
1183         * @param endOfHalfDay
1184         *            The end of the half day. This would be <em>chatzos</em> for morning based times  such as <em>sof zman krias shema</em>
1185         *            and sunset or <em>tzais</em> for afternoon based times such as <em>mincha gedola</em>.
1186         * @param hours
1187         *            The number of <em>shaos zmaniyos</em> (hours) to offset the beginning of the first or second half of the day. For example,
1188         *            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
1189         *            hamincha</em>. If the number of hours is negative, it will subtract the number of <em>shaos zmaniyos</em> from the end
1190         *            of the day.
1191         * 
1192         * @return the <code>Date</code> of <em>zman</em> based on calculation of the first or second half of the day. If the
1193         *         calculation can't be computed such as in the Arctic Circle where there is at least one day a year where the
1194         *         sun does not rise, and one where it does not set, a <code>null</code> will be returned. See detailed explanation
1195         *         on top of the {@link AstronomicalCalendar} documentation.
1196         *
1197         * @see ComplexZmanimCalendar#getFixedLocalChatzos()
1198         */
1199        public Date getHalfDayBasedZman(Date startOfHalfDay, Date endOfHalfDay, double hours) {
1200                if (startOfHalfDay == null || endOfHalfDay == null) {
1201                        return null;
1202                }
1203                long shaahZmanis = getHalfDayBasedShaahZmanis(startOfHalfDay, endOfHalfDay);
1204                if (shaahZmanis == Long.MIN_VALUE) { //defensive, should not be needed
1205                        return null;
1206                }
1207                if (hours >= 0) { // forward from start a day
1208                        return getTimeOffset(startOfHalfDay, shaahZmanis * hours);
1209                } else { // subtract from end of day
1210                        return getTimeOffset(endOfHalfDay, shaahZmanis * hours);
1211                }
1212        }
1213        
1214        /**
1215         * A utility method to calculate the length of a <em>sha'ah zmanis</em> based on 1/6 of a 6-hour day.
1216         * @param startOfHalfDay The start of the half-day. This would be <em>alos</em> or sunrise for the first half of the day,
1217         *            or <em>chatzos</em> for the second half of the day.
1218         * @param endOfHalfDay The end of the half-day. This would be <em>chatzos</em> for the first half of the day, or sunset or
1219         *            <em>tzais</em> for the second half of the day.
1220         * @return The <code>long</code> millisecond length of a <em>shaah zmanis</em> based on 1/6 of a half-day. If the calculation
1221         *         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,
1222         *         and one where it does not set, {@link Long#MIN_VALUE} will be returned. See detailed explanation on top of the
1223         *         {@link AstronomicalCalendar} documentation.
1224         * @see #getHalfDayBasedZman(Date, Date, double)
1225         * @see #isUseAstronomicalChatzosForOtherZmanim()
1226         * @todo Consider adjusting various shaah zmanis times to use this.
1227         */
1228        public long getHalfDayBasedShaahZmanis(Date startOfHalfDay, Date endOfHalfDay) {
1229                if (startOfHalfDay == null || endOfHalfDay == null) {
1230                        return Long.MIN_VALUE;
1231                }
1232                return (endOfHalfDay.getTime() - startOfHalfDay.getTime()) / 6;
1233        }
1234}