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}