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