Skip to content

Commit

Permalink
Molad and other events
Browse files Browse the repository at this point in the history
  • Loading branch information
Assaf Sapir committed Apr 13, 2024
1 parent 1904dba commit aca0434
Show file tree
Hide file tree
Showing 9 changed files with 395 additions and 1 deletion.
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions hdate/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ version = { workspace = true }


[dependencies]
bitflags = "2.5.0"
chrono = { workspace = true }
hdate_core = { path = "../hdate_core", version = "0.1.0" }
142 changes: 142 additions & 0 deletions hdate/src/event.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
use crate::Hdate;
use bitflags::bitflags;
use chrono::NaiveDate;

/// Holiday flags for Event
#[derive(Clone, Debug, PartialEq)]
pub struct Flags(u32);

bitflags! {
impl Flags: u32 {
const None = 0;
/// Chag, yontiff, yom tov
const Chag = 0x000001;
/// Light candles 18 minutes before sundown
const LightCandles = 0x000002;
// End of holiday (end of Yom Tov)
const YomTovEnds = 0x000004;
/// Observed only in the Diaspora
const ChulOnly = 0x000008;
/// Observed only in Israel
const IsraelOnly = 0x000010;
/// Light candles in the evening at Tzeit time (3 small stars)
const LightCandlesTzeis = 0x000020;
/// Candle-lighting for Chanukah
const ChanukahCandles = 0x000040;
/// Rosh Chodesh; beginning of a new Hebrew month
const RoshChodesh = 0x000080;
/// Minor fasts like Tzom Tammuz; Ta'anit Esther, ...
const MinorFast = 0x000100;
/// Shabbat Shekalim, Zachor, ...
const SpecialShabbat = 0x000200;
/// Weekly sedrot on Saturdays
const ParshaHashavua = 0x000400;
/// Daily page of Talmud (Bavli)
const DafYomi = 0x000800;
/// Days of the Omer
const OmerCount = 0x001000;
/// Yom HaShoah, Yom HaAtzma'ut, ...
const ModernHoliday = 0x002000;
/// Yom Kippur and Tish'a B'Av
const MajorFast = 0x004000;
/// On the Saturday before Rosh Chodesh
const ShabbatMevarchim = 0x008000;
/// Molad
const Molad = 0x010000;
/// Yahrzeit or Hebrew Anniversary
const UserEvent = 0x020000;
/// Daily Hebrew date ("11th of Sivan, 5780")
const HebrewDate = 0x040000;
/// A holiday that's not major, modern, rosh chodesh, or a fast day
const MinorHoliday = 0x080000;
/// Evening before a major or minor holiday
const Erev = 0x100000;
/// Chol haMoed, intermediate days of Pesach or Sukkot
const CholHamoed = 0x200000;
/// Mishna Yomi
const MishnaYomi = 0x400000;
/// Yom Kippur Katan, minor day of atonement on the day preceeding each Rosh Chodesh
const YomKippurKatan = 0x800000;
/// Daily page of Jerusalem Talmud (Yerushalmi)
const YerushalmiYomi = 0x1000000;
/// Nach Yomi
const NachYomi = 0x2000000;
/// Daily Learning
const DailyLearning = 0x4000000;
}
}

#[derive(Clone, Debug, PartialEq)]
pub struct Event {
pub date: Hdate,
pub description: String,
pub mask: Flags,
}

impl Event {
pub fn new(date: Hdate, description: String, mask: Flags) -> Self {
Self {
date,
description,
mask,
}
}

/// Returns whether the event is observed in Israel.
///
/// # Examples
///
/// ```
/// use hdate::{Hdate, HebrewMonth, Event, Flags};
///
/// let event = Event::new(
/// Hdate::from_ymd(5749, HebrewMonth::Sivan, 7),
/// "Shavuot II".to_string(),
/// Flags::Chag | Flags::ChulOnly,
/// );
///
/// assert!(!event.observed_in_israel());
///
/// let event = Event::new(
/// Hdate::from_ymd(5749, HebrewMonth::Kislev, 26),
/// "Chanukah: 3 Candles".to_string(),
/// Flags::None
/// );
///
/// assert!(event.observed_in_israel());
/// ```
pub fn observed_in_israel(&self) -> bool {
!self.mask.intersects(Flags::ChulOnly)
}

/// Returns whether the event is observed in the Diaspora.
///
/// # Example
///
/// ```
/// use hdate::{Hdate, HebrewMonth, Event, Flags};
///
/// let event = Event::new(
/// Hdate::from_ymd(5749, HebrewMonth::Sivan, 7),
/// "Shavuot II".to_string(),
/// Flags::Chag | Flags::ChulOnly,
/// );
///
/// assert!(event.observed_in_diaspora());
///
/// let event = Event::new(
/// Hdate::from_ymd(5749, HebrewMonth::Kislev, 26),
/// "Chanukah: 3 Candles".to_string(),
/// Flags::None
/// );
///
/// assert!(event.observed_in_diaspora());
/// ```
pub fn observed_in_diaspora(&self) -> bool {
!self.mask.intersects(Flags::IsraelOnly)
}

pub fn get_gregorian_date(&self) -> NaiveDate {
self.date.into()
}
}
20 changes: 20 additions & 0 deletions hdate/src/hdate.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::cmp::Ordering;
use std::fmt::Display;
use std::ops::{Add, Sub};

use chrono::{Local, NaiveDate};
Expand Down Expand Up @@ -189,6 +190,18 @@ impl TryFrom<NaiveDate> for Hdate {
}
}

impl From<Hdate> for NaiveDate {
fn from(value: Hdate) -> Self {
hdate_core::gregorian::absolute_to_gregorian(value.rd).unwrap()
}
}

impl Display for Hdate {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} {} {}", self.day, self.month, self.year)
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -234,4 +247,11 @@ mod tests {
assert_eq!(hdate2.delta_days(hdate1), -394);
assert_eq!(hdate1.delta_days(hdate1), 0);
}

#[test]
fn test_into_naive_date() {
let hdate = Hdate::from_ymd(5784, HebrewMonth::AdarII, 26);
let gregorian_date = NaiveDate::from_ymd_opt(2024, 4, 5).unwrap();
assert_eq!(Into::<NaiveDate>::into(hdate), gregorian_date);
}
}
10 changes: 10 additions & 0 deletions hdate/src/hebrew_date_event.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use crate::{Event, Flags, Hdate};

#[derive(Debug, Clone)]
pub struct HebrewDateEvent(pub Event);

impl HebrewDateEvent {
pub fn new(date: Hdate) -> Self {
Self(Event::new(date, date.to_string(), Flags::HebrewDate))
}
}
76 changes: 76 additions & 0 deletions hdate/src/holyday_event.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use chrono::NaiveDate;
use hdate_core::hebrew::HebrewMonth;

use crate::{Emoji, Event, Flags, Hdate};

pub struct HolidayEvent(Event);

impl HolidayEvent {
pub fn new(date: Hdate, description: String, mask: Flags) -> Self {
Self(Event::new(date, description, mask))
}

pub fn get_gregorian_date(&self) -> NaiveDate {
self.0.date.into()
}
}

impl Emoji for HolidayEvent {
fn get_emoji(&self) -> &str {
if self.0.mask.intersects(Flags::SpecialShabbat) {
"🕍"
} else {
"✡️"
}
}
}

pub struct RoshChodeshEvent(pub HolidayEvent);

impl RoshChodeshEvent {
pub fn new(date: Hdate) -> Self {
Self(HolidayEvent::new(
date,
format!("Rosh Chodesh {}", date.month),
Flags::RoshChodesh,
))
}
}

impl Emoji for RoshChodeshEvent {
fn get_emoji(&self) -> &str {
"🌒"
}
}

pub struct AsaraBTevetEvent(pub HolidayEvent);

impl AsaraBTevetEvent {
pub fn new(date: Hdate, mask: Flags) -> Self {
Self(HolidayEvent::new(
date,
format!("Asara B Tevet {}", date.year),
mask,
))
}
}

pub struct ShabbatMevarchimEvent {
pub holyday_event: HolidayEvent,
pub memo: String,
}

impl ShabbatMevarchimEvent {
pub fn new(date: Hdate, of_month: HebrewMonth, memo: Option<String>) -> Self {
let holyday_event = HolidayEvent::new(
date,
format!("Shabbat Mevarchim {}", of_month),
Flags::ShabbatMevarchim,
);
let memo = memo.unwrap_or_default();
Self {
holyday_event,
memo,
}
}
}
13 changes: 13 additions & 0 deletions hdate/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
pub mod event;
pub mod hdate;
pub mod hebrew_date_event;
pub mod holyday_event;
pub mod molad_event;

pub use event::Event;
pub use event::Flags;
pub use hdate::Hdate;
pub use hdate_core::hebrew::HebrewMonth;
pub use hebrew_date_event::HebrewDateEvent;
pub use holyday_event::HolidayEvent;
pub use molad_event::MoladEvent;

pub trait Emoji {
fn get_emoji(&self) -> &str;
}
Loading

0 comments on commit aca0434

Please sign in to comment.