Skip to main content

rust_zmanim/
lib.rs

1// This library is free software; you can redistribute it and/or
2// modify it under the terms of the GNU Lesser General Public
3// License as published by the Free Software Foundation; either
4// version 2.1 of the License, or (at your option) any later version.
5//
6// This library is distributed in the hope that it will be useful,
7// but WITHOUT ANY WARRANTY; without even the implied warranty of
8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
9// Lesser General Public License for more details.
10//
11// You should have received a copy of the GNU Lesser General Public
12// License along with this library; if not, see:
13// <https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html>
14
15//! # rust-zmanim
16//! `rust-zmanim` calculates solar events (such as sunrise, sunset, and
17//! twilight) and Jewish *zmanim* built on those events.
18//!
19//! ## Modules
20//! - [`astronomical_calculator`]: Low-level astronomical calculations.
21//! - [`zmanim_calculator`]: Core *zmanim* building blocks.
22//! - [`complex_zmanim_calendar`]: Stateful convenience API with many predefined
23//!   *zmanim*.
24//!
25//! ## Examples
26//!
27//! ### `zmanim_calculator`: [*Hanetz*](zmanim_calculator::hanetz) (sunrise)
28//! ```rust
29//! use jiff::{tz::TimeZone, Zoned};
30//! use rust_zmanim::prelude::*;
31//!
32//! let date = Zoned::now().date();
33//! let location = GeoLocation {
34//!     latitude: 31.778,
35//!     longitude: 35.234,
36//!     elevation: 754.0,
37//!     timezone: TimeZone::get("Asia/Jerusalem").unwrap(),
38//! };
39//!
40//! let hanetz = zmanim_calculator::hanetz(&date, &location, false).unwrap();
41//! println!("Hanetz: {}", hanetz.strftime("%H:%M:%S %Z"));
42//! ```
43//!
44//! ### `zmanim_calculator`: [*Shkia*](zmanim_calculator::shkia) (sunset)
45//! ```rust
46//! # use jiff::{tz::TimeZone, Zoned};
47//! # use rust_zmanim::prelude::*;
48//! #
49//! # let date = Zoned::now().date();
50//! # let location = GeoLocation {
51//! #     latitude: 31.778,
52//! #     longitude: 35.234,
53//! #     elevation: 754.0,
54//! #     timezone: TimeZone::get("Asia/Jerusalem").unwrap(),
55//! # };
56//! #
57//! let shkia = zmanim_calculator::shkia(&date, &location, false).unwrap();
58//! println!("Shkia: {}", shkia.strftime("%H:%M:%S %Z"));
59//! ```
60//!
61//! ### `zmanim_calculator`: [*Chatzos*](zmanim_calculator::chatzos) (Solar Noon)
62//! ```rust
63//! # use jiff::{tz::TimeZone, Zoned};
64//! # use rust_zmanim::prelude::*;
65//! #
66//! # let date = Zoned::now().date();
67//! # let location = GeoLocation {
68//! #     latitude: 31.778,
69//! #     longitude: 35.234,
70//! #     elevation: 754.0,
71//! #     timezone: TimeZone::get("Asia/Jerusalem").unwrap(),
72//! # };
73//! #
74//! let chatzos = zmanim_calculator::chatzos(&date, &location).unwrap();
75//! println!("Chatzos: {}", chatzos.strftime("%H:%M:%S %Z"));
76//! ```
77//!
78//! ### `zmanim_calculator`: [*Alos*](zmanim_calculator::alos) with a Minutes Offset
79//! ```rust
80//! # use jiff::{tz::TimeZone, Zoned};
81//! # use rust_zmanim::prelude::*;
82//! #
83//! # let date = Zoned::now().date();
84//! # let location = GeoLocation {
85//! #     latitude: 31.778,
86//! #     longitude: 35.234,
87//! #     elevation: 754.0,
88//! #     timezone: TimeZone::get("Asia/Jerusalem").unwrap(),
89//! # };
90//! #
91//! let alos_72 =
92//!     zmanim_calculator::alos(&date, &location, false, &ZmanOffset::Minutes(72.0)).unwrap();
93//! println!("Alos (72 min): {}", alos_72.strftime("%H:%M:%S %Z"));
94//! ```
95//!
96//! ### `zmanim_calculator`: [*Tzeis*](zmanim_calculator::tzeis) with a Degrees Offset
97//! ```rust
98//! # use jiff::{tz::TimeZone, Zoned};
99//! # use rust_zmanim::prelude::*;
100//! #
101//! # let date = Zoned::now().date();
102//! # let location = GeoLocation {
103//! #     latitude: 31.778,
104//! #     longitude: 35.234,
105//! #     elevation: 754.0,
106//! #     timezone: TimeZone::get("Asia/Jerusalem").unwrap(),
107//! # };
108//! #
109//! let tzeis_4_5 =
110//!     zmanim_calculator::tzeis(&date, &location, false, &ZmanOffset::Degrees(4.5)).unwrap();
111//! println!("Tzeis (4.5 deg): {}", tzeis_4_5.strftime("%H:%M:%S %Z"));
112//! ```
113//!
114//! ### `zmanim_calculator`: [*Sof Zman Shema*](zmanim_calculator::sof_zman_shema) (MGA) using *zmanis*-based *Alos* and *Tzeis*
115//! ```rust
116//! # use jiff::{tz::TimeZone, Zoned};
117//! # use rust_zmanim::prelude::*;
118//! #
119//! # let date = Zoned::now().date();
120//! # let location = GeoLocation {
121//! #     latitude: 31.778,
122//! #     longitude: 35.234,
123//! #     elevation: 754.0,
124//! #     timezone: TimeZone::get("Asia/Jerusalem").unwrap(),
125//! # };
126//! #
127//! let hanetz = zmanim_calculator::hanetz(&date, &location, false).unwrap();
128//! let shkia = zmanim_calculator::shkia(&date, &location, false).unwrap();
129//! // this is a GRA shaah zmanis, based on sunrise and sunset
130//! let shaah_zmanis_gra = zmanim_calculator::shaah_zmanis(&hanetz, &shkia);
131//!
132//! // the offset used for alos and tzeis will be based on shaos zmaniyos
133//! let offset_50_zmanis = ZmanOffset::MinutesZmaniyos {
134//!     minutes_zmaniyos: 50.0,
135//!     shaah_zmanis: shaah_zmanis_gra,
136//! };
137//! let alos_50_zmanis =
138//!     zmanim_calculator::alos(&date, &location, false, &offset_50_zmanis).unwrap();
139//! let tzeis_50_zmanis =
140//!     zmanim_calculator::tzeis(&date, &location, false, &offset_50_zmanis).unwrap();
141//!
142//! // calculate Sof Zman Shema according to the Magen Avraham, that it is
143//! // calculated from alos to tzeis
144//! let szks = zmanim_calculator::sof_zman_shema(&alos_50_zmanis, &tzeis_50_zmanis);
145//! println!(
146//!     "Sof Zman Shema (MGA 50 min zmaniyos): {}",
147//!     szks.strftime("%H:%M:%S %Z")
148//! );
149//! ```
150//!
151//! ### [`ComplexZmanimCalendar`](complex_zmanim_calendar::ComplexZmanimCalendar): Build Once, Reuse Many Times
152//! ```rust
153//! # use jiff::{tz::TimeZone, Zoned};
154//! # use rust_zmanim::prelude::*;
155//! #
156//! # let date = Zoned::now().date();
157//! # let location = GeoLocation {
158//! #     latitude: 31.778,
159//! #     longitude: 35.234,
160//! #     elevation: 754.0,
161//! #     timezone: TimeZone::get("Asia/Jerusalem").unwrap(),
162//! # };
163//! #
164//! let czc = ComplexZmanimCalendar {
165//!     geo_location: location,
166//!     date,
167//!     use_elevation: UseElevation::No,
168//! };
169//!
170//! println!("Hanetz: {}", czc.hanetz().unwrap().strftime("%H:%M:%S %Z"));
171//! println!("Shkia: {}", czc.shkia().unwrap().strftime("%H:%M:%S %Z"));
172//! ```
173//!
174//! ### `ComplexZmanimCalendar`: Premade [72-Minute *Alos*](complex_zmanim_calendar::ComplexZmanimCalendar::alos_72_minutes)
175//! ```rust
176//! # use jiff::{tz::TimeZone, Zoned};
177//! # use rust_zmanim::prelude::*;
178//! #
179//! # let date = Zoned::now().date();
180//! # let location = GeoLocation {
181//! #     latitude: 31.778,
182//! #     longitude: 35.234,
183//! #     elevation: 754.0,
184//! #     timezone: TimeZone::get("Asia/Jerusalem").unwrap(),
185//! # };
186//! #
187//! # let czc = ComplexZmanimCalendar {
188//! #     geo_location: location,
189//! #     date,
190//! #     use_elevation: UseElevation::No,
191//! # };
192//! #
193//! println!("Alos (72 min): {}", czc.alos_72_minutes().unwrap().strftime("%H:%M:%S %Z"));
194//! ```
195//!
196//! ### `ComplexZmanimCalendar`: [Generic *Tzeis*](complex_zmanim_calendar::ComplexZmanimCalendar::tzeis) with Custom Offset
197//! ```rust
198//! # use jiff::{tz::TimeZone, Zoned};
199//! # use rust_zmanim::prelude::*;
200//! #
201//! # let date = Zoned::now().date();
202//! # let location = GeoLocation {
203//! #     latitude: 31.778,
204//! #     longitude: 35.234,
205//! #     elevation: 754.0,
206//! #     timezone: TimeZone::get("Asia/Jerusalem").unwrap(),
207//! # };
208//! #
209//! # let czc = ComplexZmanimCalendar {
210//! #     geo_location: location,
211//! #     date,
212//! #     use_elevation: UseElevation::No,
213//! # };
214//! #
215//! let tzeis_7_083 = czc.tzeis(&ZmanOffset::Degrees(7.083)).unwrap();
216//! println!("Tzeis (7.083 deg): {}", tzeis_7_083.strftime("%H:%M:%S %Z"));
217//! ```
218//!
219//! ### `ComplexZmanimCalendar`: [*Tzeis* 90 Minutes *Zmaniyos* After Sunset](complex_zmanim_calendar::ComplexZmanimCalendar::tzeis_90_minutes_zmanis)
220//! ```rust
221//! # use jiff::{tz::TimeZone, Zoned};
222//! # use rust_zmanim::prelude::*;
223//! #
224//! # let date = Zoned::now().date();
225//! # let location = GeoLocation {
226//! #     latitude: 31.778,
227//! #     longitude: 35.234,
228//! #     elevation: 754.0,
229//! #     timezone: TimeZone::get("Asia/Jerusalem").unwrap(),
230//! # };
231//! #
232//! # let czc = ComplexZmanimCalendar {
233//! #     geo_location: location,
234//! #     date,
235//! #     use_elevation: UseElevation::No,
236//! # };
237//! #
238//! let tzeis_90_zmanis = czc.tzeis_90_minutes_zmanis().unwrap();
239//! println!(
240//!     "Tzeis (90 min zmaniyos): {}",
241//!     tzeis_90_zmanis.strftime("%H:%M:%S %Z")
242//! );
243//! ```
244//!
245//! ### `ComplexZmanimCalendar`: [Elevation Modes](complex_zmanim_calendar::UseElevation)
246//! ```rust
247//! # use jiff::{tz::TimeZone, Zoned};
248//! # use rust_zmanim::prelude::*;
249//! #
250//! # let date = Zoned::now().date();
251//! # let location = GeoLocation {
252//! #     latitude: 31.778,
253//! #     longitude: 35.234,
254//! #     elevation: 754.0,
255//! #     timezone: TimeZone::get("Asia/Jerusalem").unwrap(),
256//! # };
257//! #
258//! let sea_level = ComplexZmanimCalendar {
259//!     geo_location: location.clone(),
260//!     date,
261//!     use_elevation: UseElevation::No,
262//! };
263//!
264//! let elevated = ComplexZmanimCalendar {
265//!     geo_location: location,
266//!     date,
267//!     use_elevation: UseElevation::HanetzShkia,
268//! };
269//!
270//! let sea_level_hanetz = sea_level.hanetz().unwrap();
271//! let elevated_hanetz = elevated.hanetz().unwrap();
272//! println!("Sea-level hanetz: {}", sea_level_hanetz.strftime("%H:%M:%S %Z"));
273//! println!("Elevated hanetz:  {}", elevated_hanetz.strftime("%H:%M:%S %Z"));
274//! ```
275//!
276//! ## Notes
277//! - Most APIs return `Option<Zoned>`. A result of `None` means the requested
278//!   event does not occur for the requested date/location (common in high
279//!   latitudes or for deep-twilight calculations).
280//! - This crate uses NOAA-based algorithms. Returned values can be highly
281//!   precise, but real-world observations vary with atmospheric conditions,
282//!   temperature, pressure, etc.
283//! - For religious practice (*halacha lemaaseh*), **consult competent halachic
284//!   guidance**.
285//! - **Elevation based *zmanim* (even sunrise and sunset) should not be used
286//!   *lekula* without the guidance of a *posek***. According to Rabbi Dovid
287//!   Yehudah Bursztyn in his *Zmanim Kehilchasam*, 7th edition chapter 2,
288//!   section 7 (pages 181-182) and section 9 (pages 186-187), no *zmanim*
289//!   besides sunrise and sunset should use elevation. However, Rabbi Yechiel
290//!   Avrahom Zilber in the *Birur Halacha* Vol. 6 Ch. 58 Pages 34 and 42 is of
291//!   the opinion that elevation should be accounted for in *zmanim*
292//!   calculations. Related to this, Rabbi Yaakov Karp in *Shimush Zekeinim*,
293//!   Ch. 1, page 17 states that obstructing horizons should be factored into
294//!   *zmanim* calculations.
295//!
296//! ## Background
297//! This crate is a Rust port which reuses a lot of code and documentation from:
298//! - [KosherJava](https://github.com/KosherJava/zmanim)
299//! - [python-zmanim](https://github.com/pinnymz/python-zmanim)
300//!
301//! See the [KosherJava website](https://kosherjava.com) for additional
302//! background on *zmanim*.
303
304pub mod astronomical_calculator;
305pub mod complex_zmanim_calendar;
306pub mod util;
307pub mod zmanim_calculator;
308
309/// A convenience module for glob imports. `use rust_zmanim::prelude::*;`
310pub mod prelude {
311    pub use crate::astronomical_calculator;
312    pub use crate::complex_zmanim_calendar::*;
313    pub use crate::util::geolocation::GeoLocation;
314    pub use crate::zmanim_calculator::{self, ZmanOffset};
315}