heca_lib/prelude/
mod.rs

1mod location;
2use chrono::Utc;
3#[doc(inline)]
4pub use location::*;
5use serde::{Deserialize, Serialize};
6use std::fmt;
7
8#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Copy, Clone, Serialize, Deserialize)]
9pub enum Day {
10    Sunday,
11    Monday,
12    Tuesday,
13    Wednesday,
14    Thursday,
15    Friday,
16    Shabbos,
17}
18
19/// Notes: This panics if input is larger than 6, so this will be converted to a TryFrom in a future release.
20impl From<u64> for Day {
21    fn from(input: u64) -> Self {
22        match input {
23            0 => Day::Sunday,
24            1 => Day::Monday,
25            2 => Day::Tuesday,
26            3 => Day::Wednesday,
27            4 => Day::Thursday,
28            5 => Day::Friday,
29            6 => Day::Shabbos,
30            _ => panic!(format!("{} Is out of bounds", input)),
31        }
32    }
33}
34
35#[derive(Debug, PartialEq, Eq, Copy, Clone, Ord, PartialOrd)]
36pub struct Molad {
37    pub(crate) day: chrono::DateTime<Utc>,
38    pub(crate) remainder: u16,
39}
40
41impl Molad {
42    pub fn get_day_utc(&self) -> chrono::DateTime<Utc> {
43        self.day
44    }
45    pub fn get_chalakim(&self) -> u16 {
46        self.remainder
47    }
48}
49#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize, Ord, PartialOrd)]
50pub enum HebrewMonth {
51    Tishrei,
52    Cheshvan,
53    Kislev,
54    Teves,
55    Shvat,
56    Adar,
57    Adar1,
58    Adar2,
59    Nissan,
60    Iyar,
61    Sivan,
62    Tammuz,
63    Av,
64    Elul,
65}
66impl From<u64> for HebrewMonth {
67    fn from(input: u64) -> Self {
68        match input {
69            0 => HebrewMonth::Tishrei,
70            1 => HebrewMonth::Cheshvan,
71            2 => HebrewMonth::Kislev,
72            3 => HebrewMonth::Teves,
73            4 => HebrewMonth::Shvat,
74            5 => HebrewMonth::Adar,
75            6 => HebrewMonth::Adar1,
76            7 => HebrewMonth::Adar2,
77            8 => HebrewMonth::Nissan,
78            9 => HebrewMonth::Iyar,
79            10 => HebrewMonth::Sivan,
80            11 => HebrewMonth::Tammuz,
81            12 => HebrewMonth::Av,
82            13 => HebrewMonth::Elul,
83            _ => panic!(format!("{} Is out of bounds", input)),
84        }
85    }
86}
87
88///Occurs when failing to get a Hebrew Date.
89#[derive(Debug, Clone, Copy, Serialize, Deserialize, Eq, PartialEq)]
90pub enum ConversionError {
91    /// Occurs when attempting to get an Adar 1 or Adar 2 in a non-leap year.
92    ///
93    /// # Example:
94    /// ```
95    /// # use heca_lib::prelude::*;
96    /// # use heca_lib::HebrewDate;
97    /// # use std::num::NonZeroI8;
98    /// #
99    /// let result = HebrewDate::from_ymd(5778,HebrewMonth::Adar1,NonZeroI8::new(1).unwrap());
100    /// assert!(!result.is_ok());
101    /// assert_eq!(result.unwrap_err(),ConversionError::IsNotLeapYear);
102    /// ```
103    IsNotLeapYear,
104
105    /// Occurs when trying to get a Hebrew Date who's day is out of range
106    ///
107    /// # Example:
108    /// ```
109    /// # use heca_lib::prelude::*;
110    /// # use heca_lib::HebrewDate;
111    /// # use std::num::NonZeroI8;
112    /// #
113    /// let result = HebrewDate::from_ymd(5778,HebrewMonth::Adar,NonZeroI8::new(40).unwrap());
114    /// assert!(!result.is_ok());
115    /// assert_eq!(result.unwrap_err(),ConversionError::TooManyDaysInMonth(29));
116    /// ```
117    TooManyDaysInMonth(u8),
118
119    /// Occurs when attempting to get a regular Adar in a leap year.
120    ///
121    /// # Example:
122    /// ```
123    /// # use heca_lib::prelude::*;
124    /// # use heca_lib::HebrewDate;
125    /// # use std::num::NonZeroI8;
126    /// #
127    /// let result = HebrewDate::from_ymd(5779,HebrewMonth::Adar,NonZeroI8::new(1).unwrap());
128    /// assert!(!result.is_ok());
129    /// assert_eq!(result.unwrap_err(),ConversionError::IsLeapYear);
130    /// ```
131    IsLeapYear,
132    /// Occurs when attempting to get a year that is before the epoch (currently: year 3764/4).
133    ///
134    /// # Example:
135    /// ```
136    /// # use heca_lib::prelude::*;
137    /// # use heca_lib::HebrewDate;
138    /// # use std::num::NonZeroI8;
139    /// #
140    /// let result = HebrewDate::from_ymd(2448,HebrewMonth::Nissan,NonZeroI8::new(15).unwrap()); // What was the English day of the Exodus?
141    /// assert!(!result.is_ok());
142    /// assert_eq!(result.unwrap_err(),ConversionError::YearTooSmall);
143    /// ```
144    YearTooSmall,
145}
146
147impl std::error::Error for ConversionError {}
148
149impl fmt::Display for ConversionError {
150    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
151        match self {
152            ConversionError::IsNotLeapYear => write!(
153                f,
154                "Can't convert an Adar 1 or Adar 2 of a year which isn't a leap year"
155            ),
156            ConversionError::TooManyDaysInMonth(d) => {
157                write!(f, "Too many days in month. Month only has {} days", d)
158            }
159            ConversionError::IsLeapYear => write!(
160                f,
161                "Can't convert an Adar of a year which is a leap year. Specify Adar1 or Adar2"
162            ),
163            //ConversionError::MonthDoesntExist => write!(f, "Month doesn't exist"),
164            ConversionError::YearTooSmall => write!(
165                f,
166                "Cannot build calendar for years below 3764 (After Creation)"
167            ),
168        }
169    }
170}
171
172/// What Torah Readings are we looking for
173#[derive(Debug, Clone, Copy, Serialize, Deserialize, Eq, PartialEq)]
174pub enum TorahReadingType {
175    /// Yom Tov - Pesach, Shavuos, Sukkos, Shmini Atzeres/Simchas Torah, Rosh Hashana, Yom Kippur and Chol HaMoed.
176    YomTov,
177    /// Weekday Torah reading - Rosh Chodesh, Chanuka and Purim
178    Chol,
179    /// Weekly Parsha Torah reading
180    Shabbos,
181    /// One of the four special Torah portions read every winter (Shekalim, Zachor, Parah and HaChodesh).
182    SpecialParsha,
183}
184
185/// A Hebrew year can be defined by three variables:
186///
187/// 1. The first day of Rosh Hashana - Monday (the second day of the week, represented by Beis - **Ba**), Tuesday (the third day of the week, represented by Gimmel - **Ga**), Thursday (the fifth day of the week, represented by Hei - **Ha**) and Shabbos (the seventh day of the week, represented by Zayin - **Za**).
188/// 2. The length of the year, specifically, if Cheshvan and Kislev are both full (**She**leima - 30 days long), empty (**Chaseir** - 29 days long), or in regular order ("Kesidra", Cheshvan is 29 days long and Kislev is 30. So the year goes 30,29,30,29 etc.).
189/// 3. The day Pesach starts, defined as on Rosh Hashana above.
190///
191/// So, for example, 5779 is a BaShaZ year - that is, the first day of Rosh Hashana was on a Monday (Beis - **Ba**), Bosh Cheshvan and Kislev are full (Shleimah - **Sh**in),
192/// and the first night of Pesach was on Friday night (Zain - **Z** for Shabbos).
193///
194/// # Examples
195///
196///
197///
198/// ~~~
199///
200/// use heca_lib::HebrewYear;
201/// use heca_lib::prelude::*;
202/// assert_eq!(HebrewYear::new(5779)?.year_type(),MonthSchedule::BaShaZ);
203/// # Ok::<(),ConversionError>(())
204/// ~~~
205///
206/// ## Find out how often does Pesach start on which days:
207///
208/// ~~~
209///
210/// use heca_lib::HebrewYear;
211/// use heca_lib::prelude::*;
212/// let (mut thu, mut tue, mut sun, mut sat) = (0,0,0,0);
213/// for year in 3765..9999 {
214///     let t = HebrewYear::new(year)?.year_type();
215///     match t {
216///         MonthSchedule::GaChaH
217///         | MonthSchedule::BaShaH
218///         | MonthSchedule::BaChaH
219///         | MonthSchedule::ZaShaH => thu += 1,
220///
221///         MonthSchedule::HaShaG
222///         | MonthSchedule::ZaShaG
223///         | MonthSchedule::ZaChaG
224///         | MonthSchedule::BaChaG => tue += 1,
225///
226///         MonthSchedule::HaShA
227///         | MonthSchedule::ZaChA
228///         | MonthSchedule::HaChA => sun += 1,
229///         
230///         MonthSchedule::HaKaZ
231///         | MonthSchedule::BaShaZ
232///         | MonthSchedule::GaKaZ => sat += 1,
233///     }
234/// }
235/// assert_eq!(thu, 1782);
236/// assert_eq!(tue, 1988);
237/// assert_eq!(sun, 718); // <-- Note, that Pesach falls out on a Motzei Shabbos only 10% of the time.
238/// assert_eq!(sat, 1746);
239/// # Ok::<(),ConversionError>(())
240///
241///
242/// ~~~
243///
244/// ## Find out when will Pesach start on Motzei Shabbos:
245///
246/// ~~~
247/// use heca_lib::HebrewYear;
248/// use heca_lib::prelude::*;
249/// let mut years: Vec<u64> = Vec::new();
250/// for year in 5780..5880 {
251///     let t = HebrewYear::new(year).unwrap().year_type();
252///     match t {
253///         MonthSchedule::HaShA
254///         | MonthSchedule::ZaChA
255///         | MonthSchedule::HaChA => years.push(year),
256///
257///         _ => { }
258///         
259///     }
260/// }
261/// assert_eq!(years, vec![5781, 5785, 5805, 5808, 5812, 5832, 5835, 5839, 5859, 5863] ); // <-- We'll have two of them over the next few years, and then Pesach won't fall out on Motzei Shabbos for twenty years!
262///
263/// ~~~
264///
265#[derive(Debug, Clone, Copy, Serialize, Deserialize, Eq, PartialEq)]
266pub enum MonthSchedule {
267    BaChaG,
268    BaShaH,
269    GaChaH,
270    HaKaZ,
271    HaShA,
272    ZaChA,
273    ZaShaG,
274
275    BaChaH,
276    BaShaZ,
277    GaKaZ,
278    HaChA,
279    HaShaG,
280    ZaChaG,
281    ZaShaH,
282}