Source code for hebrewcal.religious.zmanim

"""Zmanim - the halachic times of the day.

Seasonal ("proportional") hours divide the daylight span into twelve. The GRA day
runs from sunrise to sunset; the MGA day runs from dawn to nightfall at 16.1
degrees. Deadlines are expressed as a number of seasonal hours after the start of
the relevant day. Each method returns a timezone-aware datetime, or None at high
latitudes where a required event does not occur.
"""

from __future__ import annotations

import datetime

from hebrewcal.astro.location import Location
from hebrewcal.astro.solar import dawn, dusk, solar_noon, sunrise, sunset
from hebrewcal.calendars.gregorian import GregorianDate

_ALOT_DEPRESSION = 16.1
_MISHEYAKIR_DEPRESSION = 11.0
_TZEIT_DEPRESSION = 8.5


def _add(
    start: datetime.datetime | None, hours: float, hour_length: datetime.timedelta | None
) -> datetime.datetime | None:
    if start is None or hour_length is None:
        return None
    return start + hour_length * hours


[docs] class Zmanim: """Halachic times for a date and location.""" def __init__(self, date: GregorianDate, location: Location) -> None: self._date = date self._loc = location # Anchor events. def sunrise(self) -> datetime.datetime | None: return sunrise(self._date, self._loc) def sunset(self) -> datetime.datetime | None: return sunset(self._date, self._loc) def chatzot(self) -> datetime.datetime: return solar_noon(self._date, self._loc)
[docs] def alot_hashachar(self, degrees: float = _ALOT_DEPRESSION) -> datetime.datetime | None: """Dawn at the given solar depression (default 16.1°, the MGA opinion).""" return dawn(self._date, self._loc, degrees)
[docs] def alot_hashachar_fixed(self, minutes: float = 72.0) -> datetime.datetime | None: """Dawn as a fixed number of clock minutes before sunrise (default 72).""" sr = self.sunrise() return None if sr is None else sr - datetime.timedelta(minutes=minutes)
[docs] def misheyakir(self, degrees: float = _MISHEYAKIR_DEPRESSION) -> datetime.datetime | None: """Earliest tallit/tefillin time at the given depression (default 11°).""" return dawn(self._date, self._loc, degrees)
[docs] def tzeit_hakochavim(self, degrees: float = _TZEIT_DEPRESSION) -> datetime.datetime | None: """Nightfall (three stars) at the given depression (default 8.5°).""" return dusk(self._date, self._loc, degrees)
[docs] def tzeit_fixed(self, minutes: float = 42.0) -> datetime.datetime | None: """Nightfall as a fixed number of clock minutes after sunset (default 42).""" ss = self.sunset() return None if ss is None else ss + datetime.timedelta(minutes=minutes)
[docs] def tzeit_rabbeinu_tam(self, minutes: float = 72.0) -> datetime.datetime | None: """Rabbeinu Tam nightfall: a fixed number of minutes after sunset (default 72).""" ss = self.sunset() return None if ss is None else ss + datetime.timedelta(minutes=minutes)
# Seasonal-hour lengths. def _gra_hour(self) -> datetime.timedelta | None: sr, ss = self.sunrise(), self.sunset() if sr is None or ss is None: return None return (ss - sr) / 12 def _mga_hour(self) -> datetime.timedelta | None: start = self.alot_hashachar() end = dusk(self._date, self._loc, _ALOT_DEPRESSION) if start is None or end is None: return None return (end - start) / 12 # GRA deadlines (from sunrise). def sof_zman_shma_gra(self) -> datetime.datetime | None: return _add(self.sunrise(), 3, self._gra_hour()) def sof_zman_tefilla_gra(self) -> datetime.datetime | None: return _add(self.sunrise(), 4, self._gra_hour()) # MGA deadlines (from dawn). def sof_zman_shma_mga(self) -> datetime.datetime | None: return _add(self.alot_hashachar(), 3, self._mga_hour()) def sof_zman_tefilla_mga(self) -> datetime.datetime | None: return _add(self.alot_hashachar(), 4, self._mga_hour()) # Afternoon (GRA seasonal hours from sunrise). def mincha_gedola(self) -> datetime.datetime | None: return _add(self.sunrise(), 6.5, self._gra_hour()) def mincha_ketana(self) -> datetime.datetime | None: return _add(self.sunrise(), 9.5, self._gra_hour()) def plag_hamincha(self) -> datetime.datetime | None: return _add(self.sunrise(), 10.75, self._gra_hour())