Skip to main content

rust_zmanim/complex_zmanim_calendar/
czc_struct.rs

1use crate::{
2    astronomical_calculator,
3    complex_zmanim_calendar::cache::ZmanCache,
4    util::geolocation::GeoLocation,
5    zmanim_calculator::{
6        self,
7        ZmanOffset::{self, Degrees, Minutes, MinutesZmaniyos},
8    },
9};
10
11use jiff::{SignedDuration, Zoned, civil::Date};
12
13/// Struct to store a 4-dimensional location and settings, to simplify getting
14/// many *zmanim* for the same location. Has premade methods for many common
15/// (and uncommon) *zmanim*. (see `impl` block)
16///
17/// Construct with [`ComplexZmanimCalendar::new`]. The underlying solar events
18/// are computed lazily and cached per instance, so calculating many *zmanim*
19/// for the same date and location is cheap. The cache makes this type
20/// `!Sync`; to share a calendar across threads, clone it.
21#[derive(Debug, Clone)]
22pub struct ComplexZmanimCalendar {
23    geo_location: GeoLocation,
24    date: Date,
25    use_elevation: UseElevation,
26    cache: ZmanCache,
27}
28
29/// Cached solar events are ignored; two calendars are equal when their
30/// location, date, and elevation setting are equal.
31impl PartialEq for ComplexZmanimCalendar {
32    fn eq(&self, other: &Self) -> bool {
33        self.geo_location == other.geo_location
34            && self.date == other.date
35            && self.use_elevation == other.use_elevation
36    }
37}
38
39/// Where unspecified, when sunrise and sunset are mentioned in the calculation
40/// of other *zmanim*, they will be sea-level or elevation-based depending on
41/// the value of `use_elevation`
42///
43/// **Elevation-based *zmanim* (even sunrise and sunset) should not be used
44/// *lekula* without the guidance of a *posek***. See the [root
45/// documentation](crate) for more details.
46///
47/// Many of the methods return `None` if the sun does not reach the specified
48/// position below the horizon at this location and date (common in polar
49/// regions).
50impl ComplexZmanimCalendar {
51    /// Returns a new `ComplexZmanimCalendar` for the given location, day, and
52    /// elevation setting
53    #[must_use]
54    pub fn new(geo_location: GeoLocation, date: Date, use_elevation: UseElevation) -> Self {
55        Self {
56            geo_location,
57            date,
58            use_elevation,
59            cache: ZmanCache::default(),
60        }
61    }
62
63    /// Location at which to calculate *zmanim*
64    #[must_use]
65    pub fn geo_location(&self) -> &GeoLocation {
66        &self.geo_location
67    }
68
69    /// Day for which to calculate *zmanim*
70    #[must_use]
71    pub fn date(&self) -> Date {
72        self.date
73    }
74
75    /// When to account for elevation. See [`UseElevation`]
76    #[must_use]
77    pub fn use_elevation(&self) -> UseElevation {
78        self.use_elevation
79    }
80
81    /// Sets the day for which to calculate *zmanim*, clearing the cached solar
82    /// events
83    pub fn set_date(&mut self, date: Date) {
84        self.date = date;
85        self.cache = ZmanCache::default();
86    }
87
88    /// Sets the location at which to calculate *zmanim*, clearing the cached
89    /// solar events
90    pub fn set_geo_location(&mut self, geo_location: GeoLocation) {
91        self.geo_location = geo_location;
92        self.cache = ZmanCache::default();
93    }
94
95    /// Sets when to account for elevation. Cached solar events are kept, as
96    /// they are stored per physical event, not per elevation setting
97    pub fn set_use_elevation(&mut self, use_elevation: UseElevation) {
98        self.use_elevation = use_elevation;
99    }
100
101    // Cached solar events. All zmanim methods reach the astronomical layer
102    // through one of these, so each underlying event is computed only once per
103    // calendar instance.
104    fn cached_sunrise(&self, use_elevation: bool) -> Option<Zoned> {
105        let cell = if use_elevation {
106            &self.cache.elevation_sunrise
107        } else {
108            &self.cache.sea_level_sunrise
109        };
110        cell.get_or_init(|| zmanim_calculator::hanetz(self.date, &self.geo_location, use_elevation))
111            .clone()
112    }
113
114    fn cached_sunset(&self, use_elevation: bool) -> Option<Zoned> {
115        let cell = if use_elevation {
116            &self.cache.elevation_sunset
117        } else {
118            &self.cache.sea_level_sunset
119        };
120        cell.get_or_init(|| zmanim_calculator::shkia(self.date, &self.geo_location, use_elevation))
121            .clone()
122    }
123
124    fn cached_solar_noon(&self) -> Option<Zoned> {
125        self.cache
126            .solar_noon
127            .get_or_init(|| zmanim_calculator::chatzos_hayom(self.date, &self.geo_location))
128            .clone()
129    }
130
131    fn cached_solar_midnight(&self) -> Option<Zoned> {
132        self.cache
133            .solar_midnight
134            .get_or_init(|| zmanim_calculator::chatzos_halayla(self.date, &self.geo_location))
135            .clone()
136    }
137
138    fn cached_sunrise_offset_by_degrees(&self, degrees: f64) -> Option<Zoned> {
139        let key = degrees.to_bits();
140        if let Some((_, cached)) = self
141            .cache
142            .sunrise_by_degrees
143            .borrow()
144            .iter()
145            .find(|(k, _)| *k == key)
146        {
147            return cached.clone();
148        }
149        let result = astronomical_calculator::sunrise_offset_by_degrees(
150            self.date,
151            &self.geo_location,
152            astronomical_calculator::GEOMETRIC_ZENITH + degrees,
153        );
154        self.cache
155            .sunrise_by_degrees
156            .borrow_mut()
157            .push((key, result.clone()));
158        result
159    }
160
161    fn cached_sunset_offset_by_degrees(&self, degrees: f64) -> Option<Zoned> {
162        let key = degrees.to_bits();
163        if let Some((_, cached)) = self
164            .cache
165            .sunset_by_degrees
166            .borrow()
167            .iter()
168            .find(|(k, _)| *k == key)
169        {
170            return cached.clone();
171        }
172        let result = astronomical_calculator::sunset_offset_by_degrees(
173            self.date,
174            &self.geo_location,
175            astronomical_calculator::GEOMETRIC_ZENITH + degrees,
176        );
177        self.cache
178            .sunset_by_degrees
179            .borrow_mut()
180            .push((key, result.clone()));
181        result
182    }
183
184    // Basics
185    /// Returns *alos hashachar* (dawn) based on either declination of the sun
186    /// below the horizon, a fixed time offset, or a minutes *zmaniyos*
187    /// (temporal minutes) offset before sunrise
188    #[must_use]
189    pub fn alos(&self, offset: &ZmanOffset) -> Option<Zoned> {
190        match offset {
191            Degrees(deg) => self.cached_sunrise_offset_by_degrees(*deg),
192            _ => Some(zmanim_calculator::offset_before_event(
193                &self.cached_sunrise(self.use_elevation.to_bool(false))?,
194                offset,
195            )),
196        }
197    }
198
199    /// Returns sea level sunrise
200    #[must_use]
201    pub fn sea_level_sunrise(&self) -> Option<Zoned> {
202        self.cached_sunrise(false)
203    }
204
205    /// Returns sea level sunset
206    #[must_use]
207    pub fn sea_level_sunset(&self) -> Option<Zoned> {
208        self.cached_sunset(false)
209    }
210
211    /// Returns elevation-adjusted sunrise
212    #[must_use]
213    pub fn elevation_sunrise(&self) -> Option<Zoned> {
214        self.cached_sunrise(true)
215    }
216
217    /// Returns elevation-adjusted sunset
218    #[must_use]
219    pub fn elevation_sunset(&self) -> Option<Zoned> {
220        self.cached_sunset(true)
221    }
222
223    /// Returns *hanetz*, or sunrise. Will be elevation-adjusted or not
224    /// depending on `use_elevation`
225    #[must_use]
226    pub fn hanetz(&self) -> Option<Zoned> {
227        self.cached_sunrise(self.use_elevation.to_bool(true))
228    }
229
230    /// Returns *shkia*, or sunset. Will be elevation-adjusted or not depending
231    /// on `use_elevation`
232    #[must_use]
233    pub fn shkia(&self) -> Option<Zoned> {
234        self.cached_sunset(self.use_elevation.to_bool(true))
235    }
236
237    /// Returns sunrise, for use internally. Will be elevation-adjusted only if
238    /// `use_elevation == All`
239    #[must_use]
240    fn zmanim_sunrise(&self) -> Option<Zoned> {
241        self.cached_sunrise(self.use_elevation.to_bool(false))
242    }
243
244    /// Returns sunset, for use internally. Will be elevation-adjusted only if
245    /// `use_elevation == All`
246    #[must_use]
247    fn zmanim_sunset(&self) -> Option<Zoned> {
248        self.cached_sunset(self.use_elevation.to_bool(false))
249    }
250
251    /// Returns the latest *zman krias shema* (time to recite *Shema* in the
252    /// morning) according to the opinion of the *Magen Avraham* (MGA) based on
253    /// *alos* and *tzeis* being given offset from sunrise and sunset,
254    /// respectively.
255    #[must_use]
256    pub fn sof_zman_shema_mga(&self, offset: &ZmanOffset) -> Option<Zoned> {
257        Some(zmanim_calculator::sof_zman_shema(
258            &self.alos(offset)?,
259            &self.tzeis(offset)?,
260        ))
261    }
262
263    /// Returns the latest *zman tefila* (time to recite *shacharis* in the
264    /// morning) according to the opinion of the *Magen Avraham* (MGA) based on
265    /// *alos* and *tzeis* being the given offset from sunrise and sunset,
266    /// respectively.
267    #[must_use]
268    pub fn sof_zman_tefila_mga(&self, offset: &ZmanOffset) -> Option<Zoned> {
269        Some(zmanim_calculator::sof_zman_tefila(
270            &self.alos(offset)?,
271            &self.tzeis(offset)?,
272        ))
273    }
274
275    /// Returns the latest *zman biur chametz* (the latest time for burning
276    /// *chametz* on *Erev Pesach*) according to the opinion of the *Magen
277    /// Avraham* (MGA) based on *alos* and *tzeis* being the given offset
278    /// from sunrise and sunset, respectively.
279    #[must_use]
280    pub fn sof_zman_biur_chametz_mga(&self, offset: &ZmanOffset) -> Option<Zoned> {
281        Some(zmanim_calculator::sof_zman_biur_chametz(
282            &self.alos(offset)?,
283            &self.tzeis(offset)?,
284        ))
285    }
286
287    /// Returns Astronomical *chatzos* (noon)
288    #[must_use]
289    pub fn chatzos_hayom(&self) -> Option<Zoned> {
290        self.cached_solar_noon()
291    }
292
293    /// Returns *chatzos hayom* calculated as halfway between [sea level
294    /// sunrise](ComplexZmanimCalendar::sea_level_sunrise) and [sea level
295    /// sunset](ComplexZmanimCalendar::sea_level_sunset). Many are of the
296    /// opinion that *chatzos* is calculated as the midpoint between sunrise and
297    /// sunset, despite it not being the most accurate way to calculate it. A
298    /// day starting at *alos* and ending at *tzeis* using the same time or
299    /// degree offset would also return the same time. In reality due to
300    /// lengthening or shortening of day, this is not necessarily [the exact
301    /// midpoint](ComplexZmanimCalendar::chatzos_hayom) of the day, but it is
302    /// very close. See [The Definition of
303    /// *Chatzos*](https://kosherjava.com/2020/07/02/definition-of-chatzos/)
304    /// for a detailed explanation of the ways to calculate *Chatzos*.
305    #[must_use]
306    pub fn chatzos_hayom_as_half_day(&self) -> Option<Zoned> {
307        Some(zmanim_calculator::chatzos_hayom_as_half_day(
308            &self.sea_level_sunrise()?,
309            &self.sea_level_sunset()?,
310        ))
311    }
312
313    /// Returns Astronomical *chatzos halayla* **at the end of the day** (the
314    /// last zman of the day returned by the calendar, that may actually be
315    /// after midnight of the day it is being calculated for).
316    ///
317    /// For example, if calculating it for the date of *Erev Pesach*, the
318    /// calculation will be for *Leil Pesach* to allow you to use the *zman* as
319    /// *sof zman achilas matza*.
320    #[must_use]
321    pub fn chatzos_halayla(&self) -> Option<Zoned> {
322        self.cached_solar_midnight()
323    }
324
325    /// Returns *mincha gedola* according to the opinion of the *Magen Avraham*
326    /// (MGA) based on *alos* and *tzeis* being the given offset from sunrise
327    /// and sunset, respectively.
328    #[must_use]
329    pub fn mincha_gedola_mga(&self, offset: &ZmanOffset) -> Option<Zoned> {
330        Some(zmanim_calculator::mincha_gedola(
331            &self.alos(offset)?,
332            &self.tzeis(offset)?,
333        ))
334    }
335
336    /// Returns *samuch lemincha ketana* according to the opinion of the *Magen
337    /// Avraham* (MGA) based on *alos* and *tzeis* being the given offset
338    /// from sunrise and sunset, respectively.
339    #[must_use]
340    pub fn samuch_lemincha_ketana_mga(&self, offset: &ZmanOffset) -> Option<Zoned> {
341        Some(zmanim_calculator::samuch_lemincha_ketana(
342            &self.alos(offset)?,
343            &self.tzeis(offset)?,
344        ))
345    }
346
347    /// Returns *mincha ketana* according to the opinion of the *Magen Avraham*
348    /// (MGA) based on *alos* and *tzeis* being the given offset from sunrise
349    /// and sunset, respectively.
350    #[must_use]
351    pub fn mincha_ketana_mga(&self, offset: &ZmanOffset) -> Option<Zoned> {
352        Some(zmanim_calculator::mincha_ketana(
353            &self.alos(offset)?,
354            &self.tzeis(offset)?,
355        ))
356    }
357
358    /// Returns *plag hamincha* according to the opinion of the *Magen Avraham*
359    /// (MGA) based on *alos* and *tzeis* being the given offset from sunrise
360    /// and sunset, respectively.
361    #[must_use]
362    pub fn plag_mga(&self, offset: &ZmanOffset) -> Option<Zoned> {
363        Some(zmanim_calculator::plag_hamincha(
364            &self.alos(offset)?,
365            &self.tzeis(offset)?,
366        ))
367    }
368
369    /// Returns *mincha gedola* calculated as 30 minutes after *chatzos* and not
370    /// 1/2 of a *shaah zmanis* after *chatzos* as calculated by
371    /// [`zmanim_calculator::mincha_gedola`]. See
372    /// [`zmanim_calculator::mincha_gedola_30_minutes`] for more details
373    #[must_use]
374    pub fn mincha_gedola_30_minutes(&self) -> Option<Zoned> {
375        Some(self.cached_solar_noon()? + SignedDuration::from_mins(30))
376    }
377
378    /// Returns *tzeis* (nightfall) based on either declination of the sun below
379    /// the horizon, a fixed time offset, or a minutes *zmaniyos* (temporal
380    /// minutes) offset after sunset
381    #[must_use]
382    pub fn tzeis(&self, offset: &ZmanOffset) -> Option<Zoned> {
383        match offset {
384            Degrees(deg) => self.cached_sunset_offset_by_degrees(*deg),
385            _ => Some(zmanim_calculator::offset_after_event(
386                &self.cached_sunset(self.use_elevation.to_bool(false))?,
387                offset,
388            )),
389        }
390    }
391
392    /// Returns *shaah zmanis* (temporal hour) according to the opinion of the
393    /// *Magen Avraham* (MGA) based on *alos* and *tzeis* being the given
394    /// offset from sunrise and sunset, respectively.
395    #[must_use]
396    pub fn shaah_zmanis_mga(&self, offset: &ZmanOffset) -> Option<SignedDuration> {
397        Some(zmanim_calculator::shaah_zmanis(
398            &self.alos(offset)?,
399            &self.tzeis(offset)?,
400        ))
401    }
402
403    // GRA
404    /// Returns the latest *Zman Shema* (time to recite *Shema* in the morning)
405    /// that is 3 *shaos zmaniyos* (solar hours) after
406    /// sunrise according the GRA. The day is
407    /// calculated from sunrise to sunset.
408    #[must_use]
409    pub fn sof_zman_shema_gra(&self) -> Option<Zoned> {
410        Some(zmanim_calculator::sof_zman_shema(
411            &self.zmanim_sunrise()?,
412            &self.zmanim_sunset()?,
413        ))
414    }
415
416    /// Returns the latest *zman tefila* (time to recite *shacharis* in the
417    /// morning) that is 4 *shaos zmaniyos* (solar hours) after
418    /// sunrise according GRA.
419    /// The day is calculated from sunrise to sunset
420    #[must_use]
421    pub fn sof_zman_tefila_gra(&self) -> Option<Zoned> {
422        Some(zmanim_calculator::sof_zman_tefila(
423            &self.zmanim_sunrise()?,
424            &self.zmanim_sunset()?,
425        ))
426    }
427
428    /// Returns the latest time for burning *chametz* on *Erev
429    /// Pesach* according to the opinion of the GRA. This time is 5 hours into
430    /// the day based on the opinion of the GRA that the day is calculated from
431    /// sunrise to sunset. Since this library does not implement a calendar,
432    /// this method will return the *zman* any day of the year.
433    #[must_use]
434    pub fn sof_zman_biur_chametz_gra(&self) -> Option<Zoned> {
435        Some(self.zmanim_sunrise()? + (self.shaah_zmanis_gra()? * 5))
436    }
437
438    /// Returns *mincha gedola* calculated as 6.5 *shaos zmaniyos* (solar hours)
439    /// after sunrise, according to the GRA.
440    #[must_use]
441    pub fn mincha_gedola_gra(&self) -> Option<Zoned> {
442        Some(zmanim_calculator::mincha_gedola(
443            &self.zmanim_sunrise()?,
444            &self.zmanim_sunset()?,
445        ))
446    }
447
448    /// Returns the later of
449    /// [`mincha_gedola_gra`](ComplexZmanimCalendar::mincha_gedola_gra)
450    /// and
451    /// [`mincha_gedola_30_minutes`](ComplexZmanimCalendar::mincha_gedola_30_minutes)
452    /// . In the winter when 1/2 of a
453    /// [GRA *shaah zmanis*](ComplexZmanimCalendar::shaah_zmanis_gra)
454    /// is less than 30 minutes
455    /// [`mincha_gedola_30_minutes`](ComplexZmanimCalendar::mincha_gedola_30_minutes)
456    /// will be returned, otherwise
457    /// [`mincha_gedola_gra`](ComplexZmanimCalendar::mincha_gedola_gra)
458    ///  will be returned
459    #[must_use]
460    pub fn mincha_gedola_gra_greater_than_30_minutes(&self) -> Option<Zoned> {
461        let mg_30 = self.mincha_gedola_30_minutes()?;
462        let mg_gra = self.mincha_gedola_gra()?;
463        Some(mg_30.max(mg_gra))
464    }
465
466    /// Returns *samuch lemincha ketana* (near *mincha
467    /// ketana*), that is half an hour before [*mincha
468    /// ketana*](ComplexZmanimCalendar::mincha_ketana_gra) or is 9 *shaos
469    /// zmaniyos* (solar hours) after sunrise, calculated according to the GRA
470    /// using a day starting at sunrise and ending at sunset. This is the
471    /// time that eating or other activity can't begin prior to praying
472    /// *mincha*. See the *Mechaber* and *Mishna Berurah* 232 and 249:2.
473    #[must_use]
474    pub fn samuch_lemincha_ketana_gra(&self) -> Option<Zoned> {
475        Some(self.zmanim_sunrise()? + (self.shaah_zmanis_gra()? * 9))
476    }
477
478    /// Returns *mincha ketana* calculated as 9.5 *shaos zmaniyos* (solar hours)
479    /// after sunrise, according to the GRA.
480    #[must_use]
481    pub fn mincha_ketana_gra(&self) -> Option<Zoned> {
482        Some(zmanim_calculator::mincha_ketana(
483            &self.zmanim_sunrise()?,
484            &self.zmanim_sunset()?,
485        ))
486    }
487
488    /// Returns *plag hamincha* calculated as 10.75 *shaos zmaniyos* (solar
489    /// hours) after sunrise, according to the GRA.
490    #[must_use]
491    pub fn plag_gra(&self) -> Option<Zoned> {
492        Some(zmanim_calculator::plag_hamincha(
493            &self.zmanim_sunrise()?,
494            &self.zmanim_sunset()?,
495        ))
496    }
497
498    /// Returns a *shaah zmanis* according to the opinion of the GRA.
499    /// This calculation divides the day based on the opinion of the *GRA* that
500    /// the day runs from sunrise to sunset. The day is split into 12 equal
501    /// parts with each one being a *shaah zmanis*
502    #[must_use]
503    pub fn shaah_zmanis_gra(&self) -> Option<SignedDuration> {
504        Some(zmanim_calculator::shaah_zmanis(
505            &self.zmanim_sunrise()?,
506            &self.zmanim_sunset()?,
507        ))
508    }
509
510    // Baal HaTanya
511    /// Returns the *Baal Hatanya*'s *alos* (dawn) calculated as the time when
512    /// the sun is 16.9&deg; below the eastern geometric horizon before sunrise.
513    /// It is based on the calculation that the time between dawn and
514    /// [*hanetz amiti*](ComplexZmanimCalendar::hanetz_amiti_baal_hatanya)
515    /// (sunrise) is 72 minutes, the time that is takes to walk 4 *mil* at
516    /// 18 minutes a *mil* (*Rambam* and others). The sun's position at 72
517    /// minutes before *hanetz amiti* (sunrise) in Jerusalem around the
518    /// equinox / equilux is 16.9&deg; below geometric zenith.
519    #[must_use]
520    pub fn alos_baal_hatanya(&self) -> Option<Zoned> {
521        self.alos(&Degrees(16.9))
522    }
523
524    /// **Note: *hanetz amiti* is used only for
525    /// calculating certain other *zmanim*. For practical purposes, daytime
526    /// *mitzvos* like *shofar* and *lulav* should not be done until after the
527    /// normal time for [*hanetz*](ComplexZmanimCalendar::hanetz).**
528    ///
529    /// Returns the *Baal Hatanya*'s *hanetz amiti* (sunrise). This forms the
530    /// base for the *Baal Hatanya*'s dawn-based
531    /// calculations that are calculated as a dip below the horizon before
532    /// sunrise. According to the *Baal Hatanya*, *hanetz amiti*, or true
533    /// (halachic) sunrise, is when the top of the sun's disk is visible at an
534    /// elevation similar to the mountains of *Eretz Yisrael*. The time is
535    /// calculated as the point at which the center of the sun's disk is
536    /// 1.583&deg; below the horizon. This degree-based calculation can be found
537    /// in Rabbi Shalom Dov Ber Levine's commentary on The *Baal Hatanya*'s
538    /// *Seder Hachnasas Shabbos*. From an elevation of 546 meters, the top of
539    /// *Har Hacarmel*, the sun disappears when it is 1&deg; 35' or 1.583&deg;
540    /// below the sea level horizon. This in turn is based on the *Gemara
541    /// Shabbos* 35a. There are other opinions brought down by Rabbi Levine,
542    /// including Rabbi Yosef Yitzchok Feigelstock who calculates it as the
543    /// degrees below the horizon 4 minutes after sunset in *Yerushalayim* (on
544    /// the equinox). That is brought down as 1.583&deg;. This is identical to
545    /// the 1&deg; 35' *zman* and is probably a typo and should be 1.683&deg;.
546    /// These calculations are used by most *Chabad* calendars that use the
547    /// *Baal Hatanya*'s *zmanim*.
548    #[must_use]
549    pub fn hanetz_amiti_baal_hatanya(&self) -> Option<Zoned> {
550        self.alos(&Degrees(1.583))
551    }
552
553    /// **Note: *shkiah amiti* is used only for calculating certain other
554    /// *zmanim*. For practical purposes, all daytime *mitzvos* should be
555    /// completed before the normal time for
556    /// [*shkiah*](ComplexZmanimCalendar::shkia).**
557    ///
558    /// Returns the *Baal Hatanya*'s *shkiah amiti* (sunset). This forms the
559    /// base for the *Baal Hatanya*'s dusk-based
560    /// calculations that are calculated as a dip below the horizon after
561    /// sunset. According to the *Baal Hatanya*, *shkiah amiti*, true (halachic)
562    /// sunset, is when the top of the sun's disk disappears from view at an
563    /// elevation similar to the mountains of *Eretz Yisrael*. This time is
564    /// calculated as the point at which the center of the sun's disk is 1.583
565    /// degrees below the horizon.
566    #[must_use]
567    pub fn shkia_amiti_baal_hatanya(&self) -> Option<Zoned> {
568        self.tzeis(&Degrees(1.583))
569    }
570
571    /// Returns the *Baal Hatanya*'s *shaah zmanis* (temporal hour). This
572    /// forms the base for the *Baal Hatanya*'s day based calculations that are
573    /// calculated as a 1.583&deg; dip below the horizon after sunset. According
574    /// to the *Baal Hatanya*, *shkiah amiti*, true (halachic) sunset, is when
575    /// the top of the sun's disk disappears from view at an elevation similar
576    /// to the mountains of *Eretz Yisrael*. This time is calculated as the
577    /// point at which the center of the sun's disk is 1.583 degrees below the
578    /// horizon. The calculations are based on a day from [*hanetz
579    /// amiti*](ComplexZmanimCalendar::hanetz_amiti_baal_hatanya) to
580    /// [*shkiah amiti*](ComplexZmanimCalendar::shkia_amiti_baal_hatanya). The
581    /// day is split into 12 equal parts with each one being a *shaah
582    /// zmanis*.
583    #[must_use]
584    pub fn shaah_zmanis_baal_hatanya(&self) -> Option<SignedDuration> {
585        self.shaah_zmanis_mga(&Degrees(1.583))
586    }
587
588    /// Returns the *Baal Hatanya*'s *sof zman krias shema*
589    /// (latest time to recite *Shema* in the morning). This time is 3
590    /// of the [*Baal Hatanya*'s temporal
591    /// hours](ComplexZmanimCalendar::shaah_zmanis_baal_hatanya) after [*hanetz
592    /// amiti*](ComplexZmanimCalendar::hanetz_amiti_baal_hatanya) (sunrise)
593    /// based on the opinion of the *Baal Hatanya* that the day is
594    /// calculated from sunrise to sunset.
595    #[must_use]
596    pub fn sof_zman_shema_baal_hatanya(&self) -> Option<Zoned> {
597        self.sof_zman_shema_mga(&Degrees(1.583))
598    }
599
600    /// Returns the *Baal Hatanya*'s *sof zman tefila* (latest
601    /// time to recite the morning prayers). This time is 4 of the [*Baal
602    /// Hatanya*'s temporal
603    /// hours](ComplexZmanimCalendar::shaah_zmanis_baal_hatanya) after [*hanetz
604    /// amiti*](ComplexZmanimCalendar::hanetz_amiti_baal_hatanya) (sunrise)
605    /// based on the opinion of the *Baal Hatanya* that the day is
606    /// calculated from sunrise to sunset.
607    #[must_use]
608    pub fn sof_zman_tefila_baal_hatanya(&self) -> Option<Zoned> {
609        self.sof_zman_tefila_mga(&Degrees(1.583))
610    }
611
612    /// Returns the latest time for burning *chametz* on *Erev
613    /// Pesach* according to the opinion of the Baal Hatanya. This time is 5
614    /// of the [*Baal Hatanya*'s temporal
615    /// hours](ComplexZmanimCalendar::shaah_zmanis_baal_hatanya) after [*hanetz
616    /// amiti*](ComplexZmanimCalendar::hanetz_amiti_baal_hatanya) (sunrise)
617    /// based on the opinion of the *Baal Hatanya* that the day is
618    /// calculated from sunrise to sunset. Since this library does not
619    /// implement a calendar, this method will return the *zman* any day of
620    /// the year.
621    #[must_use]
622    pub fn sof_zman_biur_chametz_baal_hatanya(&self) -> Option<Zoned> {
623        self.sof_zman_biur_chametz_mga(&Degrees(1.583))
624    }
625
626    /// Returns the *Baal Hatanya*'s *mincha gedola*. *Mincha
627    /// gedola* is the earliest time one can pray *mincha*. The *Rambam* is
628    /// of the opinion that it is better to delay *mincha* until *mincha
629    /// ketana* while the *Rash*, *Tur*, GRA and others are of the opinion
630    /// that *mincha* can be prayed *lechatchila* starting at *mincha
631    /// gedola*. This is calculated as 6.5 of the [*Baal Hatanya*'s temporal
632    /// hours](ComplexZmanimCalendar::shaah_zmanis_baal_hatanya) after [*hanetz
633    /// amiti*](ComplexZmanimCalendar::hanetz_amiti_baal_hatanya) (sunrise).
634    /// This calculation is based on the opinion of the *Baal Hatanya* that
635    /// the day is calculated from sunrise to sunset.
636    #[must_use]
637    pub fn mincha_gedola_baal_hatanya(&self) -> Option<Zoned> {
638        self.mincha_gedola_mga(&Degrees(1.583))
639    }
640
641    /// Returns the later of
642    /// [`mincha_gedola_baal_hatanya`](ComplexZmanimCalendar::mincha_gedola_baal_hatanya)
643    /// and
644    /// [`mincha_gedola_30_minutes`](ComplexZmanimCalendar::mincha_gedola_30_minutes)
645    /// . In the winter when 1/2 of a
646    /// [*Baal Hatanya shaah
647    /// zmanis*](ComplexZmanimCalendar::shaah_zmanis_baal_hatanya)
648    /// is less than 30 minutes
649    /// [`mincha_gedola_30_minutes`](ComplexZmanimCalendar::mincha_gedola_30_minutes)
650    /// will be returned, otherwise
651    /// [`mincha_gedola_baal_hatanya`](ComplexZmanimCalendar::mincha_gedola_baal_hatanya)
652    ///  will be returned
653    #[must_use]
654    pub fn mincha_gedola_baal_hatanya_greater_than_30_minutes(&self) -> Option<Zoned> {
655        let mg_30 = self.mincha_gedola_30_minutes()?;
656        let mg_bht = self.mincha_gedola_baal_hatanya()?;
657        Some(mg_30.max(mg_bht))
658    }
659
660    /// Returns the *Baal Hatanya*'s *mincha ketana*. This is the
661    /// preferred earliest time to pray *mincha* in the opinion of the *Rambam*
662    /// and others. For more information on this see the documentation on
663    /// *mincha gedola*. This is calculated as 9.5 of the [*Baal Hatanya*'s
664    /// temporal hours](ComplexZmanimCalendar::shaah_zmanis_baal_hatanya) after
665    /// [*hanetz amiti*](ComplexZmanimCalendar::hanetz_amiti_baal_hatanya)
666    /// (sunrise). This calculation is calculated based on the opinion of
667    /// the *Baal Hatanya* that the day is calculated from sunrise to
668    /// sunset.
669    #[must_use]
670    pub fn mincha_ketana_baal_hatanya(&self) -> Option<Zoned> {
671        self.mincha_ketana_mga(&Degrees(1.583))
672    }
673
674    /// Returns the *Baal Hatanya*'s *plag hamincha*. This is
675    /// calculated as 10.75 of the [*Baal Hatanya*'s temporal
676    /// hours](ComplexZmanimCalendar::shaah_zmanis_baal_hatanya) after *hanetz
677    /// amiti* (sunrise). This calculation is calculated based on the
678    /// opinion of the *Baal Hatanya* that the day is calculated from
679    /// sunrise to sunset.
680    #[must_use]
681    pub fn plag_baal_hatanya(&self) -> Option<Zoned> {
682        self.plag_mga(&Degrees(1.583))
683    }
684
685    /// Returns *tzeis* (nightfall) when the sun is 6&deg; below
686    /// the western geometric horizon (90&deg;) after sunset. This calculation
687    /// is based on the position of the sun 24 minutes after sunset in Jerusalem
688    /// around the equinox / equilux, which is 6&deg; below geometric zenith.
689    #[must_use]
690    pub fn tzeis_baal_hatanya(&self) -> Option<Zoned> {
691        self.tzeis(&Degrees(6.0))
692    }
693
694    // Rav Moshe Feinstein
695    /// Returns fixed local *chatzos*. See
696    /// [`crate::zmanim_calculator::fixed_local_chatzos_hayom`] for more
697    /// details.
698    #[must_use]
699    pub fn fixed_local_chatzos_hayom(&self) -> Option<Zoned> {
700        zmanim_calculator::fixed_local_chatzos_hayom(self.date, &self.geo_location)
701    }
702
703    /// Returns Rav Moshe Feinstein's opinion of the calculation of
704    /// *sof zman krias shema* (latest time to recite *Shema* in the morning)
705    /// according to the opinion of the *Magen Avraham* (MGA) that the day is
706    /// calculated from dawn to nightfall, but calculated using the first half
707    /// of the day only. The half a day starts at *alos* defined as 18&deg; and
708    /// ends at fixed local *chatzos*. *Sof Zman Shema* is 3 *shaos
709    /// zmaniyos* (solar hours) after *alos* or half of this half-day.
710    #[must_use]
711    pub fn sof_zman_shema_mga_alos_18_to_fixed_local_chatzos(&self) -> Option<Zoned> {
712        let alos = self.alos_18_degrees()?;
713        let chatzos = self.fixed_local_chatzos_hayom()?;
714        Some(zmanim_calculator::half_day_based_zman(&alos, &chatzos, 3.0))
715    }
716
717    /// Returns Rav Moshe Feinstein's opinion of the calculation of
718    /// *sof zman krias shema* (latest time to recite *Shema* in the morning)
719    /// according to the opinion of the *Magen Avraham* (MGA) that the day is
720    /// calculated from dawn to nightfall, but calculated using the first half
721    /// of the day only. The half a day starts at *alos* defined as 16.1&deg;
722    /// and ends at fixed local *chatzos*. *Sof Zman Shema* is 3 *shaos
723    /// zmaniyos* (solar hours) after this *alos* or half of this half-day.
724    #[must_use]
725    pub fn sof_zman_shema_mga_alos_16_1_to_fixed_local_chatzos(&self) -> Option<Zoned> {
726        let alos = self.alos_16_1_degrees()?;
727        let chatzos = self.fixed_local_chatzos_hayom()?;
728        Some(zmanim_calculator::half_day_based_zman(&alos, &chatzos, 3.0))
729    }
730
731    /// Returns Rav Moshe Feinstein's opinion of the calculation of
732    /// *sof zman krias shema* (latest time to recite *Shema* in the morning)
733    /// according to the opinion of the *Magen Avraham* (MGA) that the day is
734    /// calculated from dawn to nightfall, but calculated using the first half
735    /// of the day only. The half a day starts at *alos* defined as 90 minutes
736    /// before sunrise and ends at fixed local *chatzos*. *Sof Zman Shema* is 3
737    /// *shaos zmaniyos* (solar hours) after this *alos* or half of this
738    /// half-day.
739    #[must_use]
740    pub fn sof_zman_shema_mga_90_minutes_to_fixed_local_chatzos(&self) -> Option<Zoned> {
741        let alos = self.alos_90_minutes()?;
742        let chatzos = self.fixed_local_chatzos_hayom()?;
743        Some(zmanim_calculator::half_day_based_zman(&alos, &chatzos, 3.0))
744    }
745
746    /// Returns Rav Moshe Feinstein's opinion of the calculation of
747    /// *sof zman krias shema* (latest time to recite *Shema* in the morning)
748    /// according to the opinion of the *Magen Avraham* (MGA) that the day is
749    /// calculated from dawn to nightfall, but calculated using the first half
750    /// of the day only. The half a day starts at *alos* defined as 72 minutes
751    /// before sunrise and ends at fixed local *chatzos*. *Sof Zman Shema* is 3
752    /// *shaos zmaniyos* (solar hours) after this *alos* or half of this
753    /// half-day.
754    #[must_use]
755    pub fn sof_zman_shema_mga_72_minutes_to_fixed_local_chatzos(&self) -> Option<Zoned> {
756        let alos = self.alos_72_minutes()?;
757        let chatzos = self.fixed_local_chatzos_hayom()?;
758        Some(zmanim_calculator::half_day_based_zman(&alos, &chatzos, 3.0))
759    }
760
761    /// Returns Rav Moshe Feinstein's opinion of the calculation of
762    /// *sof zman krias shema* (latest time to recite *Shema* in the morning)
763    /// according to the opinion of the GRA that the day is calculated from
764    /// sunrise to sunset, but calculated using the first half of the day only.
765    /// The half a day starts at sunrise and ends at fixed local *chatzos*. *Sof
766    /// Zman Shema* is 3 *shaos zmaniyos* (solar hours) after sunrise or half of
767    /// this half-day.
768    #[must_use]
769    pub fn sof_zman_shema_gra_sunrise_to_fixed_local_chatzos(&self) -> Option<Zoned> {
770        let alos = self.zmanim_sunrise()?;
771        let chatzos = self.fixed_local_chatzos_hayom()?;
772        Some(zmanim_calculator::half_day_based_zman(&alos, &chatzos, 3.0))
773    }
774
775    /// Returns Rav Moshe Feinstein's opinion of the calculation of
776    /// *sof zman tefila* (the latest time to recite the morning
777    /// prayers) according to the opinion of the GRA that the day is calculated
778    /// from sunrise to sunset, but calculated using the first half of the day
779    /// only. The half a day starts at sunrise and ends at fixed local
780    /// *chatzos*. *Sof zman tefila* is 4 *shaos zmaniyos* (solar hours) after
781    /// sunrise or 2/3 of this half-day.
782    #[must_use]
783    pub fn sof_zman_tefila_gra_sunrise_to_fixed_local_chatzos(&self) -> Option<Zoned> {
784        let alos = self.zmanim_sunrise()?;
785        let chatzos = self.fixed_local_chatzos_hayom()?;
786        Some(zmanim_calculator::half_day_based_zman(&alos, &chatzos, 4.0))
787    }
788
789    /// Returns Rav Moshe Feinstein's opinion of the calculation of
790    /// mincha gedola, the earliest time one can pray mincha that is 30 minutes
791    /// after fixed local *chatzos*.
792    #[must_use]
793    pub fn mincha_gedola_gra_fixed_local_chatzos_30_minutes(&self) -> Option<Zoned> {
794        self.fixed_local_chatzos_hayom()?
795            .checked_add(SignedDuration::from_mins(30))
796            .ok()
797    }
798
799    /// Returns Rav Moshe Feinstein's opinion of the calculation of
800    /// mincha ketana (the preferred time to recite the mincha prayers according
801    /// to the opinion of the Rambam and others) calculated according to the GRA
802    /// that is 3.5 *shaos zmaniyos* (solar hours) after fixed local *chatzos*.
803    #[must_use]
804    pub fn mincha_ketana_gra_fixed_local_chatzos_to_sunset(&self) -> Option<Zoned> {
805        let chatzos = self.fixed_local_chatzos_hayom()?;
806        let sunset = self.zmanim_sunset()?;
807        chatzos
808            .checked_add(sunset.duration_since(&chatzos) / 12 * 7)
809            .ok()
810    }
811
812    /// Returns Rav Moshe Feinstein's opinion of the calculation of
813    /// plag hamincha. This method returns plag hamincha calculated according to
814    /// the GRA that the day ends at sunset and is 4.75 *shaos zmaniyos* (solar
815    /// hours) after fixed local *chatzos*.
816    #[must_use]
817    pub fn plag_gra_fixed_local_chatzos_to_sunset(&self) -> Option<Zoned> {
818        let chatzos = self.fixed_local_chatzos_hayom()?;
819        let sunset = self.zmanim_sunset()?;
820        chatzos
821            .checked_add(sunset.duration_since(&chatzos) / 24 * 19)
822            .ok()
823    }
824
825    /// Method to return *tzeis* (dusk) calculated as 50 minutes after
826    /// sunset. This method returns
827    /// *tzeis* (nightfall) based on the opinion of Rabbi Moshe Feinstein
828    /// for the New York area. This time should not be used for latitudes
829    /// other than ones similar to the latitude of the NY area.
830    #[must_use]
831    pub fn tzeis_50_minutes(&self) -> Option<Zoned> {
832        self.tzeis(&Minutes(50.0))
833    }
834
835    // Ahavat Shalom
836    /// Returns the time of *mincha gedola* based on the opinion of
837    /// Rabbi Yaakov Moshe Hillel as published in the luach of the Beis Horaah
838    /// of Yeshivat Chevrat Ahavat Shalom that *mincha gedola* is calculated as
839    /// half a *shaah zmanis* after *chatzos* with *shaos zmaniyos* calculated
840    /// based on a day starting 72 minutes before sunrise (alos 16.1&deg;) and
841    /// ending 13.5 minutes after sunset (*tzeis* 3.7&deg;). *Mincha gedola* is
842    /// the earliest time to pray *mincha*. The later of this time or 30
843    /// clock minutes after *chatzos* is returned. See
844    /// [`mincha_gedola_gra_greater_than_30_minutes`](ComplexZmanimCalendar::mincha_gedola_gra_greater_than_30_minutes)
845    /// (though that calculation is based on *mincha gedola* GRA). For more
846    /// information about *mincha gedola* see the documentation on [*mincha
847    /// gedola*](crate::zmanim_calculator::mincha_gedola).
848    #[must_use]
849    pub fn mincha_gedola_ahavat_shalom(&self) -> Option<Zoned> {
850        let chatzos = self.chatzos_hayom()?;
851        let alos_16_1 = self.alos_16_1_degrees()?;
852        let tzeis_3_7 = self.tzeis_geonim_3_7_degrees()?;
853        let mg_as = chatzos
854            .checked_add(tzeis_3_7.duration_since(&alos_16_1) / 24)
855            .ok()?;
856        let mg_30 = self.mincha_gedola_30_minutes()?;
857        Some(mg_30.max(mg_as))
858    }
859
860    /// Returns the time of *mincha ketana* based on the opinion of
861    /// Rabbi Yaakov Moshe Hillel as published in the luach of the Beis Horaah
862    /// of Yeshivat Chevrat Ahavat Shalom that *mincha ketana* is calculated as
863    /// 2.5 *shaos zmaniyos* before *tzeis* 3.8&deg; with *shaos zmaniyos*
864    /// calculated based on a day starting at *alos* 16.1&deg; and ending at
865    /// *tzeis* 3.8&deg;. *Mincha ketana* is the preferred earliest time to
866    /// pray *mincha* according to the opinion of the *Rambam* and others.
867    /// For more information on this see the documentation on [*mincha
868    /// ketana*](crate::zmanim_calculator::mincha_ketana).
869    #[must_use]
870    pub fn mincha_ketana_ahavat_shalom(&self) -> Option<Zoned> {
871        Some(zmanim_calculator::mincha_ketana(
872            &self.alos_16_1_degrees()?,
873            &self.tzeis_geonim_3_8_degrees()?,
874        ))
875    }
876
877    /// Returns the time of *plag hamincha* based on the opinion of
878    /// Rabbi Yaakov Moshe Hillel as published in the luach of the Beis Horaah
879    /// of Yeshivat Chevrat Ahavat Shalom that *plag hamincha* is
880    /// calculated as 1.25 *shaos zmaniyos* before *tzeis* 3.8&deg; with *shaos
881    /// zmaniyos* calculated based on a day starting at *alos* 16.1&deg; and
882    /// ending at *tzeis* 3.8&deg;.
883    #[must_use]
884    pub fn plag_ahavat_shalom(&self) -> Option<Zoned> {
885        Some(zmanim_calculator::plag_hamincha(
886            &self.alos_16_1_degrees()?,
887            &self.tzeis_geonim_3_8_degrees()?,
888        ))
889    }
890
891    /// Returns a *shaah zmanis* (temporal hour) used by some *zmanim*
892    /// according to the opinion of Rabbi Yaakov Moshe Hillel as published in
893    /// the luach of the Beis Horaah of Yeshivat Chevrat Ahavat Shalom that is
894    /// based on a day starting 72 minutes before sunrise in degrees (*alos*
895    /// 16.1&deg;) and ending 14 minutes after sunset in degrees (*tzeis*
896    /// 3.8&deg;). This day is split into 12 equal parts with each part
897    /// being a *shaah zmanis*. Note that with this system, *chatzos*
898    /// (midday) will not be the point that the sun is halfway across the
899    /// sky. These *shaos zmaniyos* are used for *Mincha Ketana* and *Plag
900    /// Hamincha*. The 14 minutes are based on 3/4 of an 18 minute *mil*,
901    /// with half a minute added for Rav Yosi.
902    #[must_use]
903    pub fn shaah_zmanis_alos_16_1_to_tzeis_3_8(&self) -> Option<SignedDuration> {
904        Some(zmanim_calculator::shaah_zmanis(
905            &self.alos_16_1_degrees()?,
906            &self.tzeis_geonim_3_8_degrees()?,
907        ))
908    }
909
910    /// Returns a *shaah zmanis* (temporal hour) used by some *zmanim*
911    /// according to the opinion of Rabbi Yaakov Moshe Hillel as published in
912    /// the luach of the Beis Horaah of Yeshivat Chevrat Ahavat Shalom that is
913    /// based on a day starting 72 minutes before sunrise in degrees (*alos*
914    /// 16.1&deg;) and ending 13.5 minutes after sunset in degrees (*tzeis*
915    /// 3.7&deg;). This day is split into 12 equal parts with each part
916    /// being a *shaah zmanis*. Note that with this system, *chatzos*
917    /// (midday) will not be the point that the sun is halfway across the
918    /// sky. These *shaos zmaniyos* are used for *mincha gedola* calculation.
919    #[must_use]
920    pub fn shaah_zmanis_alos_16_1_to_tzeis_3_7(&self) -> Option<SignedDuration> {
921        Some(zmanim_calculator::shaah_zmanis(
922            &self.alos_16_1_degrees()?,
923            &self.tzeis_geonim_3_7_degrees()?,
924        ))
925    }
926
927    // Ateret Torah
928    /// Returns the latest *zman krias shema* (time to recite
929    /// *Shema* in the morning) based on the calculation of *Chacham* Yosef
930    /// Harari-Raful of Yeshivat Ateret Torah, that the day starts 1/10th of the
931    /// day before sunrise and is usually calculated as ending 40 minutes after
932    /// sunset. *Shaos zmaniyos* are calculated based on this day and added to
933    /// *alos* to reach this time. This time is 3 *shaos zmaniyos* (temporal
934    /// hours) after *alos*72 zmaniyos. Note: Based on this calculation
935    /// *chatzos* will not be at midday.
936    #[must_use]
937    pub fn sof_zman_shema_ateret_torah(&self) -> Option<Zoned> {
938        Some(zmanim_calculator::sof_zman_shema(
939            &self.alos_72_minutes_zmanis()?,
940            &self.tzeis_ateret_torah()?,
941        ))
942    }
943
944    /// Returns the latest *zman tefila* (time to recite the morning
945    /// prayers) based on the calculation of *Chacham* Yosef Harari-Raful of
946    /// Yeshivat Ateret Torah, that the day starts 1/10th of the day before
947    /// sunrise and is usually calculated as ending 40 minutes after sunset.
948    /// *Shaos zmaniyos* are calculated based on this day and added to *alos* to
949    /// reach this time. This time is 4 *shaos zmaniyos* (temporal hours)
950    /// after *alos*72 *zmaniyos*. Note: Based on this calculation *chatzos*
951    /// will not be at midday.
952    #[must_use]
953    pub fn sof_zman_tefila_ateret_torah(&self) -> Option<Zoned> {
954        Some(zmanim_calculator::sof_zman_tefila(
955            &self.alos_72_minutes_zmanis()?,
956            &self.tzeis_ateret_torah()?,
957        ))
958    }
959
960    /// Returns the time of *mincha gedola* based on the calculation of
961    /// *Chacham* Yosef Harari-Raful of Yeshivat Ateret Torah, that the day
962    /// starts 1/10th of the day before sunrise and is usually calculated as
963    /// ending 40 minutes after sunset. The *Rambam* is of the opinion that it
964    /// is better to delay *mincha* until *mincha ketana* while the *Rash*,
965    /// *Tur*, GRA and others are of the opinion that *mincha* can be prayed
966    /// *lechatchila* starting at *mincha gedola*. For more information on
967    /// this see the documentation on [*mincha
968    /// gedola*](crate::zmanim_calculator::mincha_gedola).
969    /// This is calculated as 6.5 solar hours after *alos*. The calculation used
970    /// is `6.5 *` [`ComplexZmanimCalendar::shaah_zmanis_ateret_torah`] after
971    /// *alos*.
972    #[must_use]
973    pub fn mincha_gedola_ateret_torah(&self) -> Option<Zoned> {
974        Some(zmanim_calculator::mincha_gedola(
975            &self.alos_72_minutes_zmanis()?,
976            &self.tzeis_ateret_torah()?,
977        ))
978    }
979
980    /// Returns the time of *mincha ketana* based on the calculation of
981    /// *Chacham* Yosef Harari-Raful of Yeshivat Ateret Torah, that the day
982    /// starts 1/10th of the day before sunrise and is usually calculated as
983    /// ending 40 minutes after sunset. This is the preferred earliest time to
984    /// pray *mincha* according to the opinion of the *Rambam* and others. For
985    /// more information on this see the documentation on [*mincha
986    /// ketana*](crate::zmanim_calculator::mincha_ketana). This is calculated as
987    /// 9.5 solar hours after *alos*. The calculation used is 9.5 *
988    /// [`ComplexZmanimCalendar::shaah_zmanis_ateret_torah`] after *alos*.
989    #[must_use]
990    pub fn mincha_ketana_ateret_torah(&self) -> Option<Zoned> {
991        Some(zmanim_calculator::mincha_ketana(
992            &self.alos_72_minutes_zmanis()?,
993            &self.tzeis_ateret_torah()?,
994        ))
995    }
996
997    /// Returns the time of *plag hamincha* based on the calculation
998    /// of *Chacham* Yosef Harari-Raful of Yeshivat Ateret Torah, that the day
999    /// starts 1/10th of the day before sunrise and is usually calculated as
1000    /// ending 40 minutes after sunset. *Shaos zmaniyos* are calculated based on
1001    /// this day and added to *alos* to reach this time. This time is 10.75
1002    /// *shaos zmaniyos* (temporal hours) after dawn.
1003    #[must_use]
1004    pub fn plag_ateret_torah(&self) -> Option<Zoned> {
1005        Some(zmanim_calculator::plag_hamincha(
1006            &self.alos_72_minutes_zmanis()?,
1007            &self.tzeis_ateret_torah()?,
1008        ))
1009    }
1010
1011    /// Returns *tzeis* calculated as 40 minutes after sunset. Please note that
1012    /// *Chacham* Yosef Harari-Raful of Yeshivat Ateret Torah who uses this
1013    /// time, does so only for calculating various other zmanei hayom such as
1014    /// *Sof Zman Krias Shema* and *Plag Hamincha*. His calendars do not publish
1015    /// a *zman* for *tzeis*. It should also be noted that *Chacham*
1016    /// Harari-Raful provided a 25 minute *zman* for Israel. This API uses
1017    /// 40 minutes year round in any place on the globe.
1018    #[must_use]
1019    pub fn tzeis_ateret_torah(&self) -> Option<Zoned> {
1020        self.tzeis(&Minutes(40.0))
1021    }
1022
1023    /// Returns a shaah zmanis (temporal hour) according to the opinion
1024    /// of the *Chacham* Yosef Harari-Raful of Yeshivat Ateret Torah calculated
1025    /// with *alos* being 1/10th of sunrise to sunset day, or 72 minutes
1026    /// *zmaniyos* of such a day before sunrise, and *tzeis* is usually
1027    /// calculated as 40 minutes after sunset. This day is split into 12
1028    /// equal parts with each part being a shaah zmanis. Note that with this
1029    /// system, *chatzos* (midday) will not be the point that the sun is
1030    /// halfway across the sky.
1031    #[must_use]
1032    pub fn shaah_zmanis_ateret_torah(&self) -> Option<SignedDuration> {
1033        Some(zmanim_calculator::shaah_zmanis(
1034            &self.alos_72_minutes_zmanis()?,
1035            &self.tzeis_ateret_torah()?,
1036        ))
1037    }
1038
1039    // Ben Ish Chai
1040    /// Returns sunrise calculated as the time when the sun is directly due east
1041    /// (azimuth 90&deg;) in Polar regions on days that there is no
1042    /// [*hanetz*](ComplexZmanimCalendar::hanetz). If there is *hanetz* that
1043    /// day, `None` is returned.
1044    ///
1045    /// In Polar regions (the Arctic or Antarctic circles), there are days of no
1046    /// sunrise or sunset, and there are halachic opinions that during these
1047    /// periods, sunrise is reached when the sun is directly due east (azimuth
1048    /// 90°). The day-night boundary (sunset) in these opinions is when the sun
1049    /// is directly due west (azimuth 270°) returned by
1050    /// [`polar_sunset_ben_ish_chai`](ComplexZmanimCalendar::polar_sunset_ben_ish_chai).
1051    /// This is the opinion of Rabbi Yehosef Schwarz in his דברי יוסף – דרך מבוא
1052    /// השמש and דברי יוסף – תשובות, שאלה ח׳. This is brought down *lehalacha*
1053    /// by The *Ben Ish Chai* in the רב פעלים – חלק ב׳, סוד ישרים ס׳ ד׳.
1054    /// This time is close to six hours before astronomical chatzos hayom, but
1055    /// depending on the time of year and location in the Arctic / Antarctic, it
1056    /// can be up to 46 minutes before or after this time.
1057    #[must_use]
1058    pub fn polar_sunrise_ben_ish_chai(&self) -> Option<Zoned> {
1059        if self.hanetz().is_none() {
1060            astronomical_calculator::time_at_azimuth(
1061                self.date,
1062                &self.geo_location,
1063                astronomical_calculator::Azimuth::East,
1064            )
1065        } else {
1066            None
1067        }
1068    }
1069
1070    /// Returns *Plag Hamincha* in Polar regions on days that there are no
1071    /// [*hanetz*](ComplexZmanimCalendar::hanetz) and [*shkia*
1072    /// ](ComplexZmanimCalendar::shkia), calculated 10.75 *shaaos zmaniyos* of a
1073    /// day calculated starting at
1074    /// [`polar_sunrise_ben_ish_chai`](ComplexZmanimCalendar::polar_sunrise_ben_ish_chai)
1075    /// and ending at
1076    /// [`polar_sunset_ben_ish_chai`](ComplexZmanimCalendar::polar_sunset_ben_ish_chai).
1077    ///
1078    /// This is the opinion of Rabbi Yehosef Schwarz in his דברי יוסף – דרך מבוא
1079    /// השמש and דברי יוסף – תשובות, שאלה ח׳. This is brought down *lehalacha*
1080    /// by The *Ben Ish Chai* in the רב פעלים – חלק ב׳, סוד ישרים ס׳ ד׳. If
1081    /// there is sunrise or sunset on the set day, `None` will be returned.
1082    #[must_use]
1083    pub fn polar_plag_ben_ish_chai(&self) -> Option<Zoned> {
1084        Some(zmanim_calculator::plag_hamincha(
1085            &self.polar_sunrise_ben_ish_chai()?,
1086            &self.polar_sunset_ben_ish_chai()?,
1087        ))
1088    }
1089
1090    /// Returns sunset calculated as the time when the sun is directly due west
1091    /// (azimuth 270&deg;) in Polar
1092    /// regions on days
1093    /// that there is no [*shkia*](ComplexZmanimCalendar::shkia). If there is
1094    /// *shkia* that day, `None` is returned.
1095    ///
1096    /// In Polar regions (the Arctic or Antarctic circles), there are days of no
1097    /// sunrise or sunset, and there are halachic opinions that during these
1098    /// periods, sunset (the day-night boundary) is reached when the sun is
1099    /// directly due west (azimuth 270°). Sunrise in this opinion is when the
1100    /// sun is directly due east (azimuth 90°) returned by
1101    /// [`polar_sunrise_ben_ish_chai`](ComplexZmanimCalendar::polar_sunrise_ben_ish_chai).
1102    /// This is the opinion of Rabbi Yehosef Schwarz in his דברי יוסף – דרך מבוא
1103    /// השמש and דברי יוסף – תשובות, שאלה ח׳. This is brought down
1104    /// *lehalacha* by The *Ben Ish Chai* in the רב פעלים – חלק ב׳, סוד
1105    /// ישרים ס׳ ד׳. This time is close to six hours after astronomical chatzos
1106    /// hayom, but depending on the time of year and location in the Arctic /
1107    /// Antarctic, it can be up to 46 minutes before or after this time.
1108    #[must_use]
1109    pub fn polar_sunset_ben_ish_chai(&self) -> Option<Zoned> {
1110        if self.shkia().is_none() {
1111            astronomical_calculator::time_at_azimuth(
1112                self.date,
1113                &self.geo_location,
1114                astronomical_calculator::Azimuth::West,
1115            )
1116        } else {
1117            None
1118        }
1119    }
1120
1121    // Shach
1122    /// Returns the latest *zman krias shema* (time to recite *Shema* in the
1123    /// morning) calculated as 3 hours (regular clock hours and not *shaos
1124    /// zmaniyos*) before *chatzos*. Generally known as part of the "Komarno"
1125    /// *zmanim* after Rav Yitzchak Eizik of Komarno, a proponent of this
1126    /// calculation, it actually predates him a lot. It is the opinion of the
1127    /// *Shach* in the *Nekudas Hakesef* (*Yoreh Deah* 184), Rav Moshe Lifshitz
1128    /// in his commentary *Lechem Mishneh* on *Brachos* 1:2. It is next brought
1129    /// down about 100 years later by the *Yaavetz* (in his *siddur*, *Mor
1130    /// Uktziah Orach Chaim* 1, *Lechem Shamayim*, *Brachos* 1:2 and *She'elos
1131    /// Yaavetz* vol. 1 no. 40), Rav Yitzchak Eizik of Komarno in the *Ma'aseh
1132    /// Oreg* on *Mishnayos Brachos* 11:2, *Shevus Yaakov*, *Chasan Sofer* and
1133    /// others. See *Yisrael Vehazmanim* vol. 1 7:3, page 55 - 62
1134    #[must_use]
1135    pub fn sof_zman_shema_3_hrs_before_chatzos(&self) -> Option<Zoned> {
1136        self.chatzos_hayom()?
1137            .checked_sub(SignedDuration::from_hours(3))
1138            .ok()
1139    }
1140
1141    /// Returns the latest *zman* tefila (time to recite the morning prayers)
1142    /// calculated as 2 hours before *chatzos*. This is based on the opinions
1143    /// that calculate sof *zman* krias shema as [3 hours before
1144    /// *chatzos*](ComplexZmanimCalendar::sof_zman_shema_3_hrs_before_chatzos).
1145    #[must_use]
1146    pub fn sof_zman_tefila_2_hrs_before_chatzos(&self) -> Option<Zoned> {
1147        self.chatzos_hayom()?
1148            .checked_sub(SignedDuration::from_hours(2))
1149            .ok()
1150    }
1151
1152    zmanim_for_offset!(
1153        |_| Some(Degrees(16.1)),
1154        [
1155            alos_16_1_degrees => alos, alos_degrees_basedon_doc!(16.1, 72),
1156            tzeis_16_1_degrees => tzeis, tzeis_degrees_basedon_doc!(16.1, 72),
1157            shaah_zmanis_mga_16_1_degrees => shaah_zmanis_mga, shaah_mga_degrees_basedon_doc!(16.1, 72),
1158            sof_zman_shema_mga_16_1_degrees => sof_zman_shema_mga, szks_mga_degrees_doc!(16.1),
1159            sof_zman_tefila_mga_16_1_degrees => sof_zman_tefila_mga, szt_mga_degrees_doc!(16.1),
1160            sof_zman_biur_chametz_mga_16_1_degrees => sof_zman_biur_chametz_mga, sz_biur_chametz_mga_degrees_doc!(16.1),
1161            mincha_gedola_mga_16_1_degrees => mincha_gedola_mga, mg_mga_degrees_doc!(16.1),
1162            samuch_lemincha_ketana_mga_16_1_degrees => samuch_lemincha_ketana_mga, slmk_mga_degrees_doc!(16.1),
1163            mincha_ketana_mga_16_1_degrees => mincha_ketana_mga, mk_mga_degrees_doc!(16.1),
1164            plag_mga_16_1_degrees => plag_mga, plag_mga_degrees_lechumra_doc!(16.1),
1165        ]
1166    );
1167
1168    // *alos* 16.1 degrees to sunset
1169    /// Returns the latest *zman krias shema* (time to recite
1170    /// *Shema* in the morning) based on the opinion that the day starts at
1171    /// *alos* 16.1&deg; and ends at sunset. This is the opinion of the
1172    /// *Chidushei UKlalos HaRazah* and the *Menora Hatehora* as mentioned
1173    /// by *Yisrael Vehazmanim* vol 1, sec. 7, ch. 3 no. 16. Three *shaos
1174    /// zmaniyos* are calculated based on this day and added to *alos* to
1175    /// reach this time. This time is 3 *shaos zmaniyos* (solar hours) after
1176    /// dawn based on the opinion that the day is calculated from a *alos*
1177    /// 16.1&deg; to sunset.
1178    #[must_use]
1179    pub fn sof_zman_shema_alos_16_1_to_sunset(&self) -> Option<Zoned> {
1180        Some(zmanim_calculator::sof_zman_shema(
1181            &self.alos_16_1_degrees()?,
1182            &self.zmanim_sunset()?,
1183        ))
1184    }
1185
1186    /// This method should be used *lechumra* only and returns the time of *plag
1187    /// hamincha* based on the opinion that the day starts at *alos* 16.1&deg;
1188    /// and ends at sunset.
1189    ///
1190    /// 10.75 *shaos zmaniyos* are calculated based on
1191    /// this day and added to *alos* to reach this time. This time is 10.75
1192    /// *shaos zmaniyos* (temporal hours) after dawn based on the opinion
1193    /// that the day is calculated from a dawn of 16.1 degrees before
1194    /// sunrise to sunset. This returns the time of 10.75 * the calculated
1195    /// *shaah zmanis* after dawn. Since plag by this calculation can occur
1196    /// after sunset, it should only be used *lechumra*.
1197    #[must_use]
1198    pub fn plag_alos_16_1_to_sunset(&self) -> Option<Zoned> {
1199        Some(zmanim_calculator::plag_hamincha(
1200            &self.alos_16_1_degrees()?,
1201            &self.zmanim_sunset()?,
1202        ))
1203    }
1204
1205    // 16.1 degrees to *tzeis* geonim 7.083 degrees
1206    /// Returns the latest *zman krias shema* (time to recite
1207    /// *Shema* in the morning) based on the opinion that the day starts at
1208    /// *alos* 16.1&deg; and ends at *tzeis* 7.083&deg;. 3 *shaos zmaniyos*
1209    /// are calculated based on this day and added to *alos* to reach this
1210    /// time. This time is 3 *shaos zmaniyos* (temporal hours) after alos
1211    /// 16.1&deg; based on the opinion that the day is calculated from a
1212    /// *alos* 16.1&deg; to *tzeis* 7.083&deg;.
1213    #[must_use]
1214    pub fn sof_zman_shema_alos_16_1_to_tzeis_7_083(&self) -> Option<Zoned> {
1215        Some(zmanim_calculator::sof_zman_shema(
1216            &self.alos_16_1_degrees()?,
1217            &self.tzeis_geonim_7_083_degrees()?,
1218        ))
1219    }
1220
1221    /// Returns the time of *plag hamincha* based on the opinion
1222    /// that the day starts at *alos* 16.1&deg; and ends at *tzeis*
1223    /// 7.083&deg;. 10.75 *shaos zmaniyos* are calculated based on this day
1224    /// and added to *alos* to reach this time. This time is 10.75 *shaos
1225    /// zmaniyos* (temporal hours) after dawn based on the opinion that the
1226    /// day is calculated from a dawn of 16.1 degrees before sunrise to
1227    /// *tzeis* 7.083&deg;. This returns the time of 10.75 * the calculated
1228    /// *shaah zmanis* after dawn.
1229    #[must_use]
1230    pub fn plag_alos_16_1_to_tzeis_7_083(&self) -> Option<Zoned> {
1231        Some(zmanim_calculator::plag_hamincha(
1232            &self.alos_16_1_degrees()?,
1233            &self.tzeis_geonim_7_083_degrees()?,
1234        ))
1235    }
1236
1237    /// Returns a *shaah zmanis* (temporal hour) used by some *zmanim* according
1238    /// to some opinions that is based on a day starting at alos 16.1&deg;
1239    /// and ending tzais 7.083&deg;. This day is split into 12 equal parts
1240    /// with each part being a *shaah zmanis*. Note that with this system,
1241    /// *chatzos* (midday) will not be the point that the sun is halfway
1242    /// across the sky.
1243    #[must_use]
1244    pub fn shaah_zmanis_alos_16_1_to_tzeis_7_083(&self) -> Option<SignedDuration> {
1245        Some(zmanim_calculator::shaah_zmanis(
1246            &self.alos_16_1_degrees()?,
1247            &self.tzeis_geonim_7_083_degrees()?,
1248        ))
1249    }
1250
1251    zmanim_for_offset!(
1252        |_| Some(Degrees(18.0)),
1253        [
1254            alos_18_degrees => alos, alos_degrees_doc!(18),
1255            tzeis_18_degrees => tzeis, tzeis_degrees_doc!(18),
1256            shaah_zmanis_mga_18_degrees => shaah_zmanis_mga, shaah_mga_degrees_doc!(18),
1257            sof_zman_shema_mga_18_degrees => sof_zman_shema_mga, szks_mga_degrees_doc!(18),
1258            sof_zman_tefila_mga_18_degrees => sof_zman_tefila_mga, szt_mga_degrees_doc!(18),
1259            plag_mga_18_degrees => plag_mga, plag_mga_degrees_lechumra_doc!(18),
1260        ]
1261    );
1262
1263    // 19 degrees
1264    /// Returns *alos* (dawn) calculated when the sun is 19&deg;
1265    /// below the eastern geometric horizon before sunrise. This is the
1266    /// *Rambam*'s *alos* according to Rabbi Moshe Kosower's *Maaglei Tzedek*,
1267    /// page 88, *Ayeles Hashachar* Vol. I, page 12, *Yom Valayla Shel Torah*,
1268    /// Ch. 34, p. 222 and Rabbi Yaakov Shakow's *Luach Ikvei Hayom*.
1269    #[must_use]
1270    pub fn alos_19_degrees(&self) -> Option<Zoned> {
1271        self.alos(&Degrees(19.0))
1272    }
1273
1274    zmanim_for_offset!(
1275        |_| Some(Degrees(19.8)),
1276        [
1277            alos_19_8_degrees => alos, alos_degrees_basedon_doc!(19.8, 90),
1278            tzeis_19_8_degrees => tzeis, tzeis_degrees_basedon_doc!(19.8, 90),
1279            shaah_zmanis_mga_19_8_degrees => shaah_zmanis_mga, shaah_mga_degrees_basedon_doc!(19.8, 90),
1280            sof_zman_shema_mga_19_8_degrees => sof_zman_shema_mga, szks_mga_degrees_doc!(19.8),
1281            sof_zman_tefila_mga_19_8_degrees => sof_zman_tefila_mga, szt_mga_degrees_doc!(19.8),
1282            plag_mga_19_8_degrees => plag_mga, plag_mga_degrees_lechumra_doc!(19.8),
1283        ]
1284    );
1285
1286    zmanim_for_offset!(
1287        |_| Some(Degrees(26.0)),
1288        [
1289            alos_26_degrees => alos, alos_degrees_basedon_lechumra_doc!(26, 120),
1290            tzeis_26_degrees => tzeis, tzeis_degrees_basedon_doc!(26, 120),
1291            shaah_zmanis_mga_26_degrees => shaah_zmanis_mga, shaah_mga_degrees_lechumra_basedon_doc!(26, 120),
1292            plag_mga_26_degrees => plag_mga, plag_mga_degrees_lechumra_doc!(26),
1293        ]
1294    );
1295
1296    zmanim_for_offset!(
1297        |_| Some(Minutes(60.0)),
1298        [
1299            alos_60_minutes => alos, "Returns *alos* (dawn) calculated as 60 minutes before sunrise. This is the time to walk the distance of 4 *mil* at 15 minutes a *mil*. This seems to be the opinion of the *Chavas Yair* in the *Mekor Chaim, Orach Chaim* Ch. 90, though the *Mekor Chaim* in Ch. 58 and in the *Chut Hashani* Ch. 97 states that a person walks 3 and a 1/3 *mil* in an hour, or an 18-minute *mil*. Also see the *Divrei Malkiel* Vol. 4, Ch. 20, page 34) who mentions the 15 minute *mil lechumra* by baking *matzos*. Also see the *Maharik* Ch. 173 where the questioner quoting the *Ra'avan* is of the opinion that the time to walk a *mil* is 15 minutes (5 *mil* in a little over an hour). There are many who believe that there is a *ta'us sofer* (scribal error) in the *Ra'avan*, and it should be 4 *mil* in a little over an hour, or an 18-minute *mil*. Time based offset calculations are based on the opinion of the *Rishonim* who stated that the time of the *neshef* (time between dawn and sunrise) does not vary by the time of year or location but purely depends on the time it takes to walk the distance of 4 *mil*.",
1300            tzeis_60_minutes => tzeis, "Returns *tzeis hakochavim* (nightfall) based on the opinion of the *Chavas Yair* and *Divrei Malkiel* that the time to walk the distance of a mil is 15 minutes, for a total of 60 minutes for 4 *mil* after sunset. See detailed documentation explaining the 60 minute concept at [alos_60_minutes](ComplexZmanimCalendar::alos_60_minutes).",
1301            shaah_zmanis_mga_60_minutes => shaah_zmanis_mga, shaah_mga_minutes_doc!(60),
1302            plag_mga_60_minutes => plag_mga, plag_mga_minutes_doc!(60),
1303        ]
1304    );
1305
1306    zmanim_for_offset!(
1307        |_| Some(Minutes(72.0)),
1308        [
1309            alos_72_minutes => alos, alos_minutes_basedon_doc!(72, 18),
1310            tzeis_72_minutes => tzeis, "Returns *tzeis hakochavim* (nightfall) based on the opinion of *Rabbeinu Tam* that *tzeis hakochavim* is calculated as 72 minutes after sunset, the time it takes to walk 4 *mil* at 18 minutes a mil. According to the *Machtzis Hashekel* in *Orach Chaim* 235:3, the *Pri Megadim* in *Orach Chaim* 261:2 (see the *Biur Halacha*) and others (see *Hazmanim Bahalacha* 17:3 and 17:5) the 72 minutes are standard clock minutes any time of the year in any location.",
1311            shaah_zmanis_mga_72_minutes => shaah_zmanis_mga, shaah_mga_minutes_doc!(72),
1312            sof_zman_shema_mga_72_minutes => sof_zman_shema_mga, szks_mga_minutes_doc!(72),
1313            sof_zman_tefila_mga_72_minutes => sof_zman_tefila_mga, szt_mga_minutes_doc!(72),
1314            sof_zman_biur_chametz_mga_72_minutes => sof_zman_biur_chametz_mga, sz_biur_chametz_mga_minutes_doc!(72),
1315            mincha_gedola_mga_72_minutes => mincha_gedola_mga, mg_mga_minutes_doc!(72),
1316            samuch_lemincha_ketana_mga_72_minutes => samuch_lemincha_ketana_mga, slmk_mga_minutes_doc!(72),
1317            mincha_ketana_mga_72_minutes => mincha_ketana_mga, mk_mga_minutes_doc!(72),
1318            plag_mga_72_minutes => plag_mga, plag_mga_minutes_lechumra_doc!(72),
1319        ]
1320    );
1321
1322    zmanim_for_offset!(
1323        |this: &ComplexZmanimCalendar| {
1324            Some(MinutesZmaniyos {
1325                minutes_zmaniyos: 72.0,
1326                shaah_zmanis: this.shaah_zmanis_gra()?,
1327            })
1328        },
1329        [
1330            alos_72_minutes_zmanis => alos, concat!(
1331                alos_minutes_zmanis_basedon_doc!(72, 18, "1/10th"),
1332                "\nThis calculation is used in the calendars published by the Hisachdus Harabanim D'Artzos Habris Ve'Canada."
1333            ),
1334            tzeis_72_minutes_zmanis => tzeis, "Returns *tzeis hakochavim* (nightfall) calculated as 72 minutes *zmaniyos*, or 1/10th of the day after sunset. This is the way that the *Minchas Cohen* in *Ma'amar* 2:4 calculates *Rebbeinu Tam*'s time of *tzeis*. It should be noted that this calculation results in the shortest time from sunset to *tzeis* being during the winter solstice, the longest at the summer solstice and 72 clock minutes at the equinox. This does not match reality, since there is no direct relationship between the length of the day and twilight. The shortest twilight is during the equinox, the longest is during the summer solstice, and in the winter with the shortest daylight, the twilight period is longer than during the equinoxes.",
1335            shaah_zmanis_mga_72_minutes_zmanis => shaah_zmanis_mga, shaah_mga_minutes_zmanis_doc!(72, "1/10th"),
1336            sof_zman_shema_mga_72_minutes_zmanis => sof_zman_shema_mga, szks_mga_minutes_zmanis_doc!(72, "1/10th"),
1337            sof_zman_tefila_mga_72_minutes_zmanis => sof_zman_tefila_mga, szt_mga_minutes_zmanis_doc!(72, "1/10th"),
1338            sof_zman_biur_chametz_mga_72_minutes_zmanis => sof_zman_biur_chametz_mga, sz_biur_chametz_mga_minutes_zmanis_doc!(72, "1/10th"),
1339            plag_mga_72_minutes_zmanis => plag_mga, plag_mga_minutes_zmanis_lechumra_doc!(72, "1/10th"),
1340        ]
1341    );
1342
1343    zmanim_for_offset!(
1344        |_| Some(Minutes(90.0)),
1345        [
1346            alos_90_minutes => alos, alos_minutes_basedon_doc!(90, 22.5),
1347            tzeis_90_minutes => tzeis, "Returns *tzeis hakochavim* (dusk) calculated as 90 minutes after sunset. This method returns *tzeis* based on the opinion of the *Magen Avraham* that the time to walk the distance of a *mil* according to the *Rambam*'s opinion is 18 minutes, for a total of 90 minutes based on the opinion of Ula who calculated *tzeis* as 5 *mil* after *shkiah* (sunset). A similar calculation [tzeis_19_8_degrees](ComplexZmanimCalendar::tzeis_19_8_degrees) uses solar position calculations based on this time.",
1348            shaah_zmanis_mga_90_minutes => shaah_zmanis_mga, shaah_mga_minutes_doc!(90),
1349            sof_zman_shema_mga_90_minutes => sof_zman_shema_mga, szks_mga_minutes_doc!(90),
1350            sof_zman_tefila_mga_90_minutes => sof_zman_tefila_mga, szt_mga_minutes_doc!(90),
1351            plag_mga_90_minutes => plag_mga, plag_mga_minutes_lechumra_doc!(90),
1352        ]
1353    );
1354
1355    zmanim_for_offset!(
1356        |this: &ComplexZmanimCalendar| {
1357            Some(MinutesZmaniyos {
1358                minutes_zmaniyos: 90.0,
1359                shaah_zmanis: this.shaah_zmanis_gra()?,
1360            })
1361        },
1362        [
1363            alos_90_minutes_zmanis => alos, alos_minutes_zmanis_basedon_doc!(90, 22.5, "1/8th"),
1364            tzeis_90_minutes_zmanis => tzeis, concat!(
1365                tzeis_minutes_zmanis_basedon_doc!(90, 22.5, "1/8th"),
1366                " This time is known in Yiddish as the *achtel* (an eighth) *zman*."
1367            ),
1368            shaah_zmanis_mga_90_minutes_zmanis => shaah_zmanis_mga, shaah_mga_minutes_zmanis_doc!(90, "1/8th"),
1369            sof_zman_shema_mga_90_minutes_zmanis => sof_zman_shema_mga, szks_mga_minutes_zmanis_doc!(90, "1/8th"),
1370            sof_zman_tefila_mga_90_minutes_zmanis => sof_zman_tefila_mga, szt_mga_minutes_zmanis_doc!(90, "1/8th"),
1371            plag_mga_90_minutes_zmanis => plag_mga, plag_mga_minutes_zmanis_lechumra_doc!(90, "1/8th"),
1372        ]
1373    );
1374
1375    zmanim_for_offset!(
1376        |_| Some(Minutes(96.0)),
1377        [
1378            alos_96_minutes => alos, alos_minutes_basedon_doc!(96, 24),
1379            tzeis_96_minutes => tzeis, tzeis_minutes_basedon_doc!(96, 24),
1380            shaah_zmanis_mga_96_minutes => shaah_zmanis_mga, shaah_mga_minutes_doc!(96),
1381            sof_zman_shema_mga_96_minutes => sof_zman_shema_mga, szks_mga_minutes_doc!(96),
1382            sof_zman_tefila_mga_96_minutes => sof_zman_tefila_mga, szt_mga_minutes_doc!(96),
1383            plag_mga_96_minutes => plag_mga, plag_mga_minutes_lechumra_doc!(96),
1384        ]
1385    );
1386
1387    zmanim_for_offset!(
1388        |this: &ComplexZmanimCalendar| {
1389            Some(MinutesZmaniyos {
1390                minutes_zmaniyos: 96.0,
1391                shaah_zmanis: this.shaah_zmanis_gra()?,
1392            })
1393        },
1394        [
1395            alos_96_minutes_zmanis => alos, alos_minutes_zmanis_basedon_doc!(96, 22.5, "1/7.5th"),
1396            tzeis_96_minutes_zmanis => tzeis, tzeis_minutes_zmanis_basedon_doc!(96, 22.5, "1/7.5th"),
1397            shaah_zmanis_mga_96_minutes_zmanis => shaah_zmanis_mga, shaah_mga_minutes_zmanis_doc!(96, "1/7.5th"),
1398            sof_zman_shema_mga_96_minutes_zmanis => sof_zman_shema_mga, szks_mga_minutes_zmanis_doc!(96, "1/7.5th"),
1399            sof_zman_tefila_mga_96_minutes_zmanis => sof_zman_tefila_mga, szt_mga_minutes_zmanis_doc!(96, "1/7.5th"),
1400            plag_mga_96_minutes_zmanis => plag_mga, plag_mga_minutes_zmanis_lechumra_doc!(96, "1/7.5th"),
1401        ]
1402    );
1403
1404    zmanim_for_offset!(
1405        |_| Some(Minutes(120.0)),
1406        [
1407            alos_120_minutes => alos, "This method should be used *lechumra* only and returns *alos* (dawn) calculated using 120 minutes before sunrise. This is based on the time to walk the distance of 5 *mil* (Ula) at 24 minutes a *mil*. Time based offset calculations for *alos* are based on the opinion of the *Rishonim* who stated that the time of the *neshef* (time between dawn and sunrise) does not vary by the time of year or location but purely depends on the time it takes to walk the distance of 5 *mil* (Ula). Since this time is extremely early, it should only be used *lechumra*, such as not eating after this time on a fast day, and **not** as the start time for *mitzvos* that can only be performed during the day.",
1408            tzeis_120_minutes => tzeis, "Returns *tzeis hakochavim* (dusk) calculated as 120 minutes after sunset. For information on how this is calculated see the documentation on [alos_120_minutes](ComplexZmanimCalendar::alos_120_minutes).",
1409            shaah_zmanis_mga_120_minutes => shaah_zmanis_mga, shaah_mga_minutes_doc!(120),
1410            sof_zman_shema_mga_120_minutes => sof_zman_shema_mga, szks_mga_minutes_doc!(120),
1411            sof_zman_tefila_mga_120_minutes => sof_zman_tefila_mga, szt_mga_minutes_doc!(120),
1412            plag_mga_120_minutes => plag_mga, plag_mga_minutes_lechumra_doc!(120),
1413        ]
1414    );
1415
1416    zmanim_for_offset!(
1417        |this: &ComplexZmanimCalendar| {
1418            Some(MinutesZmaniyos {
1419                minutes_zmaniyos: 120.0,
1420                shaah_zmanis: this.shaah_zmanis_gra()?,
1421            })
1422        },
1423        [
1424            alos_120_minutes_zmanis => alos, "This method should be used *lechumra* only and returns *alos* (dawn) calculated using 120 minutes *zmaniyos* or 1/6th of the day before sunrise. This is based on a 24-minute *mil* so the time for 5 *mil* is 120 minutes, which is 1/6th of a day `(12 * 60) / 6 = 120`. The day is calculated from sunrise to sunset. Since this time is extremely early, it should only be used *lechumra*, such as not eating after this time on a fast day, and **not** as the start time for *mitzvos* that can only be performed during the day.",
1425            tzeis_120_minutes_zmanis => tzeis, "This method should be used *lechumra* only and returns *tzeis* (dusk) calculated using 120 minutes *zmaniyos* after sunset. Since the *zman* is extremely late and at a time when the sun is well below the 18&deg; point (scientifically the darkest point) in most places on the globe, it should only be used *lechumra*, such as delaying the start of nighttime mitzvos.",
1426            shaah_zmanis_mga_120_minutes_zmanis => shaah_zmanis_mga, "Returns a *shaah zmanis* (temporal hour) calculated using a dip of 120 minutes. This calculation divides the day based on the opinion of the *Magen Avraham* (MGA) that the day runs from dawn to dusk. Dawn for this calculation is 120 minutes before sunrise and dusk is 120 minutes after sunset. This day is split into 12 equal parts with each part being a *shaah zmanis*. This is identical to 1/6th of the day from sunrise to sunset. Since *zmanim* that use this method are extremely late or early and at a point when the sky is a long time past the 18&deg; point where the darkest point is reached, *zmanim* that use this should only be used *lechumra* only, such as delaying the start of nighttime *mitzvos*.",
1427            plag_mga_120_minutes_zmanis => plag_mga, plag_mga_minutes_zmanis_lechumra_doc!(120, "1/6th"),
1428        ]
1429    );
1430
1431    // Other Misheyakir
1432    /// Returns *misheyakir* based on the position of the sun 12.85&deg; below
1433    /// geometric zenith (90&deg;). This is based on the position of the sun
1434    /// slightly later than 57 minutes before sunrise in Jerusalem around the
1435    /// equinox / equilux. This *zman* is mentioned for use ***bish'as
1436    /// hadchak*** in the Birur Halacha Tinyana and Tlisa'ah in Orach Chaim
1437    /// siman 18 as 12.85&deg;. Actual calculations show it to be slightly more
1438    /// than 12.9&deg;, but the Birur Halacha indicates that 12.85&deg; is a
1439    /// slight *chumra* (on a *bedieved* time) VS the 12.9&deg; that 57 minutes
1440    /// calculates as (a difference of about 14 seconds at the equinox/equilux
1441    /// in Jerusalem). The *zman* of 12.9&deg; is also mentioned in the Piskei
1442    /// Tshuvos siman 18, page 190 (where a typo indicates that this is the
1443    /// degree equivalent to 60 minutes before sunrise, when in fact at that
1444    /// point the sun is about 13.5&deg; below the horizon). The 57 minute based
1445    /// time is mentioned by the Minchas Yitzchak vol. 9, siman 9 as 15 minutes
1446    /// before *alos hashachar* (though he is not clear what location he refers
1447    /// to, and does not mention a degree-based conversion). The Kaf Hachaim
1448    /// vol.1 siman 18, no. 18 states that in Yerushalayim 60 fixed minutes are
1449    /// used year round. Calculations show that 60 fixed minutes in Yerushalayim
1450    /// ranges from 13.5&deg; at the spring equinox to 11.5&deg; at the summer
1451    /// solstice. 57 minutes range from 12.9&deg; at the winter equinox to
1452    /// 11&deg; at the summer solstice. Analysis of the difference between
1453    /// 12.85&deg; and 12.9&deg;, shows that the maximum difference occurs at
1454    /// the summer solstice. In Lakewood, NJ at a latitude of 40.096&deg;, the
1455    /// maximum difference throughout the year is 23 seconds. In the winter
1456    /// where there is the greatest need for very early *misheyakir* times, the
1457    /// difference is in the 16 second range. Going north to Montreal at
1458    /// latitude 45.5&deg;, the maximum is 29 seconds and is about 18 seconds in
1459    /// the winter. Moving farther north to the elevation of Vilnius at a
1460    /// latitude of 54.68&deg;, things change. Firstly, around the summer
1461    /// solstice it will not reach that far below the horizon. On the dates that
1462    /// both can be calculated, the maximum difference can be pretty high on one
1463    /// or two days of the year (around Jul 8), with about a week having over a
1464    /// two minute difference between the two. Even at the latitude of Vilna,
1465    /// from Dec - March, the difference is about 22 seconds.
1466    #[must_use]
1467    pub fn misheyakir_12_85_degrees(&self) -> Option<Zoned> {
1468        self.alos(&Degrees(12.85))
1469    }
1470
1471    /// Returns *misheyakir* based on the position of the sun when
1472    /// it is 11.5&deg; below geometric zenith (90&deg;). This calculation is
1473    /// used for calculating *misheyakir* according to some opinions. This
1474    /// calculation is based on the position of the sun 52 minutes before
1475    /// sunrise in Jerusalem around the equinox / equilux, which calculates
1476    /// to 11.5&deg; below geometric zenith.
1477    #[must_use]
1478    pub fn misheyakir_11_5_degrees(&self) -> Option<Zoned> {
1479        self.alos(&Degrees(11.5))
1480    }
1481
1482    /// Returns *misheyakir* based on the position of the sun when
1483    /// it is 11&deg; below geometric zenith (90&deg;). This calculation is used
1484    /// for calculating *misheyakir* according to some opinions. This
1485    /// calculation is based on the position of the sun 48 minutes before
1486    /// sunrise in Jerusalem around the equinox / equilux, which calculates
1487    /// to 11&deg; below geometric zenith.
1488    #[must_use]
1489    pub fn misheyakir_11_degrees(&self) -> Option<Zoned> {
1490        self.alos(&Degrees(11.0))
1491    }
1492
1493    /// Returns *misheyakir* based on the position of the sun when
1494    /// it is 10.2&deg; below geometric zenith (90&deg;). This calculation is
1495    /// used for calculating *misheyakir* according to some opinions. This
1496    /// calculation is based on the position of the sun 45 minutes before
1497    /// sunrise in Jerusalem around the equinox which calculates to 10.2&deg;
1498    /// below geometric zenith.
1499    #[must_use]
1500    pub fn misheyakir_10_2_degrees(&self) -> Option<Zoned> {
1501        self.alos(&Degrees(10.2))
1502    }
1503
1504    /// Returns *misheyakir* based on the position of the sun when
1505    /// it is 9.5&deg; below geometric zenith (90&deg;). This calculation is
1506    /// based on Rabbi Dovid Kronglass's Calculation of 45 minutes in
1507    /// Baltimore as mentioned in *Divrei Chachamim* No. 24 brought down by
1508    /// the *Birur Halacha*, *Tinyana*, Ch. 18. This calculates to 9.5&deg;.
1509    /// Also see Rabbi Yaakov Yitzchok Neiman in *Kovetz Eitz Chaim* Vol. 9,
1510    /// p. 202 that the *Vya'an Yosef* did not want to rely on times earlier
1511    /// than 45 minutes in New York. This *zman* is also used in the
1512    /// calendars published by Rabbi Hershel Edelstein. As mentioned in
1513    /// Yisroel Vehazmanim, Rabbi Edelstein who was given the 45 minute
1514    /// *zman* by Rabbi Bick. The calendars published by the *Edot
1515    /// Hamizrach* communities also use this *zman*. This also follows the
1516    /// opinion of Rabbi Shmuel Kamenetsky who provided the time of 36 and
1517    /// 45 minutes, but did not provide a degree-based time. Since this
1518    /// *zman* depends on the level of light, Rabbi Yaakov Shakow presented
1519    /// these degree-based times to Rabbi Shmuel Kamenetsky who agreed to
1520    /// them.
1521    #[must_use]
1522    pub fn misheyakir_9_5_degrees(&self) -> Option<Zoned> {
1523        self.alos(&Degrees(9.5))
1524    }
1525
1526    /// Returns *misheyakir* based on the position of the sun when
1527    /// it is 7.65&deg; below geometric zenith (90&deg;). The degrees are based
1528    /// on a 35/36 minute *zman* around the equinox / equilux, when the
1529    /// *neshef* (twilight) is the shortest. This time is based on Rabbi
1530    /// Moshe Feinstein who writes in *Ohr Hachaim* Vol. 4, Ch. 6 that
1531    /// *misheyakir* in New York is 35-40 minutes before sunrise, something
1532    /// that is a drop less than 8&deg;. Rabbi Yisroel Taplin in *Zmanei
1533    /// Yisrael* (page 117) notes that Rabbi Yaakov Kamenetsky stated that
1534    /// it is not less than 36 minutes before sunrise (maybe it is
1535    /// 40 minutes). *Sefer Yisrael Vehazmanim* (p. 7) quotes the *Tamar
1536    /// Yifrach* in the name of the Satmar Rov that one should be stringent
1537    /// not consider *misheyakir* before 36 minutes. This is also the
1538    /// accepted *minhag* in Lakewood that is used in the Yeshiva. This
1539    /// follows the opinion of Rabbi Shmuel Kamenetsky who provided the time
1540    /// of 35/36 minutes, but did not provide a degree-based time. Since
1541    /// this *zman* depends on the level of light, Rabbi Yaakov Shakow
1542    /// presented this degree-based calculations to Rabbi Shmuel Kamenetsky
1543    /// who agreed to them.
1544    #[must_use]
1545    pub fn misheyakir_7_65_degrees(&self) -> Option<Zoned> {
1546        self.alos(&Degrees(7.65))
1547    }
1548
1549    // Bein Hashmashos Yereim
1550    /// Returns the beginning of *bein hashmashos* (twilight)
1551    /// according to the Yereim (Rabbi Eliezer of Metz) calculated as 18 minutes
1552    /// or 3/4 of a 24-minute mil before sunset. According to the Yereim, bein
1553    /// hashmashos starts 3/4 of a mil before sunset and *tzeis* or nightfall
1554    /// starts at sunset.
1555    #[must_use]
1556    pub fn bein_hashmashos_yereim_18_minutes(&self) -> Option<Zoned> {
1557        self.tzeis(&Minutes(-18.0))
1558    }
1559
1560    /// Returns the beginning of *bein hashmashos* (twilight)
1561    /// according to the Yereim (Rabbi Eliezer of Metz) calculated as the sun's
1562    /// position 3.05&deg; above the horizon around the equinox / equilux, its
1563    /// position 18 minutes or 3/4 of an 24-minute mil before sunset. According
1564    /// to the Yereim, *bein hashmashos* starts 3/4 of a mil before sunset and
1565    /// *tzeis* or nightfall starts at sunset. Note that lechumra (of about 14
1566    /// seconds) a refraction value of 0.5166&deg; as opposed to the traditional
1567    /// 0.566&deg; is used. This is more inline with the actual refraction in
1568    /// Eretz Yisrael and is brought down by Rabbi Yedidya Manet in his
1569    /// Zmanei Halacha Lema'aseh (p. 11). That is the first source that I am
1570    /// aware of that calculates degree-based Yereim zmanim. The 0.5166&deg;
1571    /// refraction is also used by the Luach Itim Lebinah. Calculating the
1572    /// Yereim's *bein hashmashos* using 18-minute based degrees is also
1573    /// suggested in the upcoming 8th edition of the zmanim Kehilchasam. For
1574    /// more details, see the article The Yereim's Bein Hashmashos.
1575    #[must_use]
1576    pub fn bein_hashmashos_yereim_3_05_degrees(&self) -> Option<Zoned> {
1577        self.tzeis(&Degrees(-3.05))
1578    }
1579
1580    /// Returns the beginning of *bein hashmashos* (twilight)
1581    /// according to the Yereim (Rabbi Eliezer of Metz) calculated as 16.875
1582    /// minutes or 3/4 of a 22.5-minute mil before sunset. According to the
1583    /// Yereim, *bein hashmashos* starts 3/4 of a mil before sunset and *tzeis*
1584    /// or nightfall starts at sunset.
1585    #[must_use]
1586    pub fn bein_hashmashos_yereim_16_875_minutes(&self) -> Option<Zoned> {
1587        self.tzeis(&Minutes(-16.875))
1588    }
1589
1590    /// Returns the beginning of *bein hashmashos* (twilight)
1591    /// according to the Yereim (Rabbi Eliezer of Metz) calculated as the sun's
1592    /// position 2.8&deg; above the horizon around the equinox / equilux, its
1593    /// position 16.875 minutes or 3/4 of an 18-minute mil before sunset.
1594    /// According to the Yereim, *bein hashmashos* starts 3/4 of a mil before
1595    /// sunset and *tzeis* or nightfall starts at sunset. Details, including how
1596    /// the degrees were calculated can be seen in the documentation of
1597    /// [`bein_hashmashos_yereim_3_05_degrees`](ComplexZmanimCalendar::bein_hashmashos_yereim_3_05_degrees).
1598    #[must_use]
1599    pub fn bein_hashmashos_yereim_2_8_degrees(&self) -> Option<Zoned> {
1600        self.tzeis(&Degrees(-2.8))
1601    }
1602
1603    /// Returns the beginning of *bein hashmashos* (twilight)
1604    /// according to the Yereim (Rabbi Eliezer of Metz) calculated as 13.5
1605    /// minutes or 3/4 of an 18-minute mil before sunset. According to the
1606    /// Yereim, *bein hashmashos* starts 3/4 of a mil before sunset and *tzeis*
1607    /// or nightfall starts at sunset.
1608    #[must_use]
1609    pub fn bein_hashmashos_yereim_13_5_minutes(&self) -> Option<Zoned> {
1610        self.tzeis(&Minutes(-13.5))
1611    }
1612
1613    /// Returns the beginning of *bein hashmashos* according to the
1614    /// Yereim (Rabbi Eliezer of Metz) calculated as the sun's position 2.1&deg;
1615    /// above the horizon around the equinox / equilux in Yerushalayim, its
1616    /// position 13.5 minutes or 3/4 of an 18-minute mil before sunset.
1617    /// According to the Yereim, *bein hashmashos* starts 3/4 of a mil before
1618    /// sunset and *tzeis* or nightfall starts at sunset. Details, including how
1619    /// the degrees were calculated can be seen in the documentation of
1620    /// [`bein_hashmashos_yereim_3_05_degrees`](ComplexZmanimCalendar::bein_hashmashos_yereim_3_05_degrees).
1621    #[must_use]
1622    pub fn bein_hashmashos_yereim_2_1_degrees(&self) -> Option<Zoned> {
1623        self.tzeis(&Degrees(-2.1))
1624    }
1625
1626    // Bein Hashmashos Rabeinu Tam
1627    /// Method to return the beginning of *bein hashmashos* of Rabbeinu Tam
1628    /// calculated when the sun is 13.24&deg; below the western geometric
1629    /// horizon (90&deg;) after sunset. This calculation is based on the
1630    /// same calculation of [*bein hashmashos* Rabbeinu Tam
1631    /// 58.5](ComplexZmanimCalendar::bein_hashmashos_rt_58_5_minutes) minutes
1632    /// but uses a degree-based calculation instead of 58.5 exact minutes.
1633    /// This calculation is based on the position of the sun 58.5 minutes
1634    /// after sunset in Jerusalem around the equinox / equilux, which
1635    /// calculates to 13.24&deg; below geometric zenith. NOTE: As per
1636    /// Yisrael Vehazmanim Vol. III page 1028, No. 50, a dip of slightly
1637    /// less than 13&deg; should be used. Calculations show that the proper
1638    /// dip to be 13.2456&deg; (truncated to 13.24 that provides about 1.5
1639    /// second earlier (*lechumra*) time) below the horizon at that time. This
1640    /// makes a difference of 1 minute and 10 seconds in Jerusalem during the
1641    /// Equinox, and 1 minute 29 seconds during the solstice as compared to the
1642    /// proper 13.24&deg; versus 13&deg;. For NY during the solstice, the
1643    /// difference is 1 minute 56 seconds.
1644    #[must_use]
1645    pub fn bein_hashmashos_rt_13_24_degrees(&self) -> Option<Zoned> {
1646        self.tzeis(&Degrees(13.24))
1647    }
1648
1649    /// Returns the beginning of *bein hashmashos* of Rabbeinu Tam
1650    /// calculated as a 58.5-minute offset after sunset. *bein hashmashos* is
1651    /// 3/4 of a mil before *tzeis* or 3 1/4 mil after sunset. With a mil
1652    /// calculated as 18 minutes, 3.25 * 18 = 58.5 minutes.
1653    #[must_use]
1654    pub fn bein_hashmashos_rt_58_5_minutes(&self) -> Option<Zoned> {
1655        self.tzeis(&Minutes(58.5))
1656    }
1657
1658    /// Returns the beginning of *bein hashmashos* based on the
1659    /// calculation of 13.5 minutes (3/4 of an 18-minute mil) before *shkiah*
1660    /// calculated as 7.083&deg;.
1661    #[must_use]
1662    pub fn bein_hashmashos_rt_13_5_minutes_before_7_083_degrees(&self) -> Option<Zoned> {
1663        self.tzeis_geonim_7_083_degrees()?
1664            .checked_sub(SignedDuration::from_secs(810))
1665            .ok()
1666    }
1667
1668    /// Returns the beginning of *bein hashmashos* of Rabbeinu Tam
1669    /// calculated according to the opinion of the Divrei Yosef (see Yisrael
1670    /// Vehazmanim) calculated 5/18th (27.77%) of the time between alos
1671    /// (calculated as 19.8&deg; before sunrise) and sunrise. This is added to
1672    /// sunset to arrive at the time for *bein hashmashos* of Rabbeinu Tam.
1673    #[must_use]
1674    pub fn bein_hashmashos_rt_2_stars(&self) -> Option<Zoned> {
1675        let sunrise = self.zmanim_sunrise()?;
1676        let alos = self.alos_19_8_degrees()?;
1677        self.zmanim_sunset()?
1678            .checked_add(sunrise.duration_since(&alos) * 5 / 18)
1679            .ok()
1680    }
1681
1682    // Other tzeis
1683    /// Returns the *tzeis hakochavim* (nightfall) based on the
1684    /// opinion of the *Geonim* calculated at the sun's position at 3.7&deg;
1685    /// below the western horizon. This is a very early *zman* and should not be
1686    /// relied on without Rabbinical guidance.
1687    #[must_use]
1688    pub fn tzeis_geonim_3_7_degrees(&self) -> Option<Zoned> {
1689        self.tzeis(&Degrees(3.7))
1690    }
1691
1692    /// Returns the *tzeis hakochavim* (nightfall) based on the
1693    /// opinion of the *Geonim* calculated at the sun's position at 3.8&deg;
1694    /// below the western horizon. This is a very early *zman* and should not be
1695    /// relied on without Rabbinical guidance.
1696    #[must_use]
1697    pub fn tzeis_geonim_3_8_degrees(&self) -> Option<Zoned> {
1698        self.tzeis(&Degrees(3.8))
1699    }
1700
1701    /// Returns the *tzeis hakochavim* (nightfall) based on the
1702    /// opinion of the *Geonim* calculated as 3/4 of a *mil*, based on a
1703    /// 22.5-minute *mil*, or 16 7/8 minutes. It is the sun's position at
1704    /// 4.42&deg; below the western horizon. This is a very early *zman* and
1705    /// should not be relied on without Rabbinical guidance.
1706    #[must_use]
1707    pub fn tzeis_geonim_4_42_degrees(&self) -> Option<Zoned> {
1708        self.tzeis(&Degrees(4.42))
1709    }
1710
1711    /// Returns the *tzeis hakochavim* (nightfall) based on the
1712    /// opinion of the *Geonim* calculated as 3/4 of a *mil* based on a
1713    /// 24-minute *mil*, or 18 minutes. It is the sun's position at 4.66&deg;
1714    /// below the western horizon. This is a very early *zman* and should
1715    /// not be relied on without Rabbinical guidance.
1716    #[must_use]
1717    pub fn tzeis_geonim_4_66_degrees(&self) -> Option<Zoned> {
1718        self.tzeis(&Degrees(4.66))
1719    }
1720
1721    /// Returns the *tzeis* (nightfall) based on the opinion of the
1722    /// *Geonim* calculated as 3/4 of a *mil* based on the sun's position at
1723    /// 4.8&deg; below the western horizon. This is based on Rabbi Leo Levi's
1724    /// calculations. This is a very early *zman* and should not be relied on
1725    /// without Rabbinical guidance.
1726    #[must_use]
1727    pub fn tzeis_geonim_4_8_degrees(&self) -> Option<Zoned> {
1728        self.tzeis(&Degrees(4.8))
1729    }
1730
1731    /// Returns the *tzeis* (nightfall) based on the opinion of the
1732    /// *Geonim* calculated at the sun's position at 5.95&deg; below below
1733    /// geometric zenith (90&deg;), calculated as the position of the sun 24
1734    /// minutes after sunset in Jerusalem around the equinox / equilux. The
1735    /// 24 minutes is based on the *Baal Hatanya*'s calculation of 18
1736    /// minutes (3/4 of a 24 minute *mil*) + 4 minutes for [*shkia
1737    /// amiti*](ComplexZmanimCalendar::shkia_amiti_baal_hatanya) + 2 minutes for
1738    /// *bein hashmashos* of Rav Yosi. See *Hazmanim Bahalacha* vol II, ch.
1739    /// 50, no. 5, p. 512-513, ch. 47, and *Yisrael Vehazmanim* Vol III, ch.
1740    /// 13, no. 53, p. 1026. Among sources he mentions for this zman is
1741    /// Rabbi Yehuda (Leo) Levi's calculations in *Jewish Chrononomy* and
1742    /// other sources. Calculations show that the time is closer to
1743    /// 5.93&deg; and was seemingly rounded to 5.95&deg;. Chabad calendars
1744    /// usually use the 6&deg;-based
1745    /// [`tzeis_baal_hatanya`](ComplexZmanimCalendar::tzeis_baal_hatanya)
1746    /// that is built on this same calculation. It should be noted that Rabbi
1747    /// Yedidya Manet in his *Zmanei HaHalacha Lema'aseh* (4th edition part 2,
1748    /// pages and 22 and 24) lists 5.88&deg; that appears to be a drop too
1749    /// early.
1750    #[must_use]
1751    pub fn tzeis_geonim_5_95_degrees(&self) -> Option<Zoned> {
1752        self.tzeis(&Degrees(5.95))
1753    }
1754
1755    /// Returns the *tzeis* (nightfall) based on the opinion of the
1756    /// *Geonim* as calculated by Rabbi Yechiel Michel Tucazinsky. It is based
1757    /// on the position of the sun no later than 31 minutes after sunset
1758    /// in Jerusalem at the height of the summer solstice and is 28 minutes
1759    /// after *shkiah* around the equinox / equilux. This computes to 6.45&deg;
1760    /// below the western horizon.
1761    #[must_use]
1762    pub fn tzeis_geonim_6_45_degrees(&self) -> Option<Zoned> {
1763        self.tzeis(&Degrees(6.45))
1764    }
1765
1766    /// Returns the *tzeis hakochavim* (nightfall) based on the
1767    /// opinion of the *Geonim* calculated when the sun's position 7.083&deg;
1768    /// (or 7&deg; 5′) below the western horizon. This is often referred to
1769    /// as 7&deg;5' or 7&deg; and 5 minutes. This calculation is based on
1770    /// the observation of 3 medium-sized stars by Dr. Baruch (Berthold)
1771    /// Cohn in his luach Tabellen enthaltend die Zeitangaben für den Beginn
1772    /// der Nacht und des Tages für die Breitengrade + 66 bis -38 published
1773    /// in Strasbourg, France in 1899. This calendar was very popular in
1774    /// Europe, and many other calendars based their time on it. Rav Dovid
1775    /// Tzvi Hoffman in his *Sh"Ut Melamed Leho'il* in an exchange of
1776    /// letters with Baruch Cohn in *Orach Chaim* 30 agreed to this *zman*
1777    /// (page 36), as did the *Sh"Ut Bnei Tziyon* and the *Tenuvas
1778    /// Sadeh*. It is very close to the time of the *Mekor Chesed* of the *Sefer
1779    /// chasidim*. It is close to the position of the sun 30 minutes after
1780    /// sunset in Jerusalem around the equinox / equilux, but not Exactly. The
1781    /// actual position of the sun 30 minutes after sunset in Jerusalem at the
1782    /// equilux is 7.205&deg; and 7.199&deg; at the equinox. See *Hazmanim
1783    /// Bahalacha* vol 2, pages 520-521 for more details.
1784    #[must_use]
1785    pub fn tzeis_geonim_7_083_degrees(&self) -> Option<Zoned> {
1786        self.tzeis(&Degrees(7.0 + (5.0 / 60.0)))
1787    }
1788
1789    /// Returns *tzeis* (nightfall) based on the opinion of the
1790    /// Geonim calculated as 45 minutes after sunset during the summer solstice
1791    /// in New York, when the *neshef* (twilight) is the longest. The sun's
1792    /// position at this time computes to 7.75&deg; below the western horizon.
1793    /// See Igros Moshe Even Haezer 4, Ch. 4 (regarding *tzeis* for *krias
1794    /// Shema*). It is also mentioned in Rabbi Heber's *Shaarei Zmanim* on in
1795    /// chapter 10 (page 87) and chapter 12 (page 108). Also see the time of 45
1796    /// minutes in Rabbi Simcha Bunim Cohen's The radiance of Shabbos as the
1797    /// earliest *zman* for New York. This *zman* is also listed in the *Divrei
1798    /// Shalom* Vol. III, chapter 75, and *Beis Av"i* Vol. III, chapter 117.
1799    /// This *zman* is also listed in the *Divrei Shalom* etc. chapter 177.
1800    /// Since this *zman* depends on the level of light, Rabbi Yaakov Shakow
1801    /// presented this degree-based calculation to Rabbi Rabbi Shmuel
1802    /// Kamenetsky who agreed to it.
1803    #[must_use]
1804    pub fn tzeis_geonim_7_67_degrees(&self) -> Option<Zoned> {
1805        self.tzeis(&Degrees(7.67))
1806    }
1807
1808    /// Returns *tzeis* (nightfall) when the sun is 8.5&deg; below the geometric
1809    /// horizon (90&deg;) after sunset, a time that Rabbi Meir Posen in his the
1810    /// *Ohr Meir* calculated that 3 small stars are visible, which is later
1811    /// than the required 3 medium stars. This calculation is based on the sun's
1812    /// position below the horizon 36 minutes after sunset in Jerusalem around
1813    /// the equinox / equilux.
1814    #[must_use]
1815    pub fn tzeis_geonim_8_5_degrees(&self) -> Option<Zoned> {
1816        self.tzeis(&Degrees(8.5))
1817    }
1818
1819    /// Returns the *tzeis* (nightfall) based on the calculations
1820    /// used in the *Luach Itim Lebinah* as the stringent time for *tzeis*. It
1821    /// is calculated at the sun's position at 9.3&deg; below the western
1822    /// horizon.
1823    #[must_use]
1824    pub fn tzeis_geonim_9_3_degrees(&self) -> Option<Zoned> {
1825        self.tzeis(&Degrees(9.3))
1826    }
1827
1828    /// Returns the *tzeis* (nightfall) based on the opinion of the
1829    /// *Geonim* calculated as 60 minutes after sunset around the equinox /
1830    /// equilux, the day that a solar hour is 60 minutes in New York. The sun's
1831    /// position at this time computes to 9.75&deg; below the western horizon.
1832    /// This is the opinion of Rabbi Eliyahu Henkin. This also follows the
1833    /// opinion of Rabbi Shmuel Kamenetsky. Rabbi Yaakov Shakow presented
1834    /// these degree-based times to Rabbi Shmuel Kamenetsky who agreed to
1835    /// them.
1836    #[must_use]
1837    pub fn tzeis_geonim_9_75_degrees(&self) -> Option<Zoned> {
1838        self.tzeis(&Degrees(9.75))
1839    }
1840
1841    // Solar position / Polar regions
1842    /// Returns the solar azimuth (in degrees, measured clockwise from due
1843    /// north) of the sun at the given datetime for this location.
1844    #[must_use]
1845    pub fn solar_azimuth(&self, instant: &Zoned) -> f64 {
1846        astronomical_calculator::solar_azimuth(instant, &self.geo_location)
1847    }
1848
1849    /// Returns the solar elevation (in degrees) of the sun at the given
1850    /// datetime for this location. The value is negative when the sun is below
1851    /// the horizon, and is based on sea level (not adjusted for altitude).
1852    #[must_use]
1853    pub fn solar_elevation(&self, instant: &Zoned) -> f64 {
1854        astronomical_calculator::solar_elevation(instant, &self.geo_location)
1855    }
1856
1857    /// Returns the percentage of a *shaah zmanis* after sunset (when `sunset`
1858    /// is `true`) or before sunrise (when `sunset` is `false`) for a given
1859    /// `degrees` offset below the horizon.
1860    ///
1861    /// For the equilux where there is a 720-minute day, passing 16.1&deg; for
1862    /// the location of Jerusalem will return about 1.2. This will work for any
1863    /// location or date, but will typically only be of interest at the
1864    /// equinox/equilux to calculate the percentage of a *shaah zmanis* for
1865    /// those who want to use the *Minchas Cohen* in *Ma'amar* 2:4 and the *Pri
1866    /// Chadash* who calculate *tzeis* as a percentage of the day after sunset.
1867    /// While the *Minchas Cohen* only applies this to 72 minutes or a 1/10 of
1868    /// the day around the world (based on the equinox / equilux in Israel),
1869    /// this method allows calculations for any degree level for any location.
1870    #[must_use]
1871    pub fn percent_of_shaah_zmanis_from_degrees(&self, degrees: f64, sunset: bool) -> Option<f64> {
1872        let sea_level_sunrise = self.sea_level_sunrise()?;
1873        let sea_level_sunset = self.sea_level_sunset()?;
1874        let twilight = if sunset {
1875            self.tzeis(&Degrees(degrees))?
1876        } else {
1877            self.alos(&Degrees(degrees))?
1878        };
1879        let shaah_zmanis = sea_level_sunset
1880            .duration_since(&sea_level_sunrise)
1881            .as_secs_f64()
1882            / 12.0;
1883        let rise_set_to_twilight = if sunset {
1884            twilight.duration_since(&sea_level_sunset).as_secs_f64()
1885        } else {
1886            sea_level_sunrise.duration_since(&twilight).as_secs_f64()
1887        };
1888        Some(rise_set_to_twilight / shaah_zmanis)
1889    }
1890}
1891
1892/// When to use elevation for *zmanim* calculations. See
1893/// [`crate`] for details.
1894#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1895pub enum UseElevation {
1896    /// Never use elevation
1897    No,
1898    /// Only use elevation directly for *hanetz* and *shkia*
1899    HanetzShkia,
1900    /// Always use elevation
1901    All,
1902}
1903
1904impl UseElevation {
1905    /// Convert the `UseElevation` into a `bool` for
1906    /// [`zmanim_calculator`](crate::zmanim_calculator) functions. The param
1907    /// `hanetz_or_shkia` should be `true` if the calling function is
1908    /// calculating *hanetz* or *shkia*, and `false` otherwise
1909    #[must_use]
1910    pub const fn to_bool(self, hanetz_or_shkia: bool) -> bool {
1911        match self {
1912            Self::No => false,
1913            Self::HanetzShkia => hanetz_or_shkia,
1914            Self::All => true,
1915        }
1916    }
1917}