#![warn(missing_docs)]
pub use chrono::{Local, Datelike, NaiveDate, Date, DateTime, Weekday};
mod eq;
pub mod before_after;
pub mod holidays;
pub mod iter;
pub use before_after::*;
pub use iter::*;
use HolidayDate::*;
pub use NthWeekday::*;
pub use Month::*;
#[derive(Debug, Clone, Copy)]
pub struct Holiday<S: ToString> {
name: S,
date: HolidayDate,
}
impl<S: ToString> Holiday<S> {
pub fn new_fixed<M: Into<Month>>(name: S, month: M, day: u32) -> Self {
Holiday {
name,
date: HolidayDate::FixedDate(DayOfMonth { month: month.into(), day }),
}
}
pub fn new_nth<N: Into<NthWeekday>, M: Into<Month>>(name: S, nth: N, weekday: Weekday, month: M) -> Self {
Holiday {
name,
date: HolidayDate::NthDate(NthWeekdayOfMonth::new(nth, weekday, month)),
}
}
pub fn name(&self) -> &S {
&self.name
}
pub fn iter(&self) -> HolidayIter<Self> {
self.into_iter()
}
pub fn in_year(&self, year: i32) -> NaiveDate {
self.after(&NaiveDate::from_ymd(year, 1, 1))
}
}
#[test]
fn holiday_in_year() {
assert_eq!(holidays::global::CHRISTMAS.in_year(2020), NaiveDate::from_ymd(2020, 12, 25));
assert_eq!(holidays::united_states::THANKSGIVING.in_year(2020), NaiveDate::from_ymd(2020, 11, 26));
assert_eq!(holidays::global::NEW_YEARS_DAY.in_year(2020), NaiveDate::from_ymd(2020, 1, 1));
assert_eq!(holidays::global::NEW_YEARS_EVE.in_year(2020), NaiveDate::from_ymd(2020, 12, 31));
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum HolidayDate {
FixedDate(DayOfMonth),
NthDate(NthWeekdayOfMonth),
}
impl HolidayDate {
pub fn iter(&self) -> HolidayIter<Self> {
self.into_iter()
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct DayOfMonth {
pub day: u32,
pub month: Month,
}
impl DayOfMonth {
pub fn new<M: Into<Month>>(day: u32, month: M) -> Self {
DayOfMonth { day, month: month.into() }
}
pub fn iter(&self) -> HolidayIter<Self> {
self.into_iter()
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct NthWeekdayOfMonth {
nth: NthWeekday,
weekday: Weekday,
month: Month,
}
impl NthWeekdayOfMonth {
pub fn new<N: Into<NthWeekday>, M: Into<Month>>(nth: N, weekday: Weekday, month: M) -> Self {
NthWeekdayOfMonth {
nth: nth.into(),
weekday,
month: month.into(),
}
}
pub fn iter(&self) -> HolidayIter<Self> {
self.into_iter()
}
}
impl From<NaiveDate> for NthWeekdayOfMonth {
fn from(date: NaiveDate) -> Self {
let mut nth = 0;
let mut loop_date = date.clone().with_day(1).expect("invalid day of month");
loop {
if loop_date.weekday() == date.weekday() {
nth += 1;
}
if loop_date >= date {
break;
}
loop_date = loop_date.succ();
}
NthWeekdayOfMonth {
nth: nth.into(),
weekday: date.weekday(),
month: date.month().into(),
}
}
}
#[allow(missing_docs)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
pub enum NthWeekday {
First = 1,
Second = 2,
Third = 3,
Fourth = 4,
Fifth = 5,
Last = 6,
}
impl From<u32> for NthWeekday {
fn from(u: u32) -> NthWeekday {
use NthWeekday::*;
match u {
0 => panic!("value must be non-zero"),
1 => First,
2 => Second,
3 => Third,
4 => Fourth,
5 => Fifth,
_ => Last,
}
}
}
impl From<NthWeekday> for u32 {
fn from(nth: NthWeekday) -> Self {
nth as u32
}
}
#[allow(missing_docs)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
pub enum Month {
January = 1,
February = 2,
March = 3,
April = 4,
May = 5,
June = 6,
July = 7,
August = 8,
September = 9,
October = 10,
November = 11,
December = 12,
}
impl Month {
pub fn from_zero(&self) -> u32 {
*self as u32 - 1
}
}
impl From<u32> for Month {
fn from(u: u32) -> Self {
match u {
1 => January,
2 => February,
3 => March,
4 => April,
5 => May,
6 => June,
7 => July,
8 => August,
9 => September,
10 => October,
11 => November,
12 => December,
u => panic!("Invalid month: '{}'", u),
}
}
}
impl From<Month> for u32 {
fn from(m: Month) -> Self {
m as u32
}
}
#[test]
fn tgives_nth_weekday_of_month() {
let tgives = NthWeekdayOfMonth::new(Fourth, Weekday::Thu, 11);
dbg!(tgives.after_today());
dbg!(tgives.before_today());
dbg!(NthWeekdayOfMonth::from(NaiveDate::from_ymd(2020, 6, 8)));
}