Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Calendar & initial impl for Matsudo #6

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 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 Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
chrono = "0.4.19"
9 changes: 9 additions & 0 deletions src/calendar.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use chrono::{DateTime, Local};

use crate::gomi::Gomi;

pub(crate) mod matsudo;

pub(crate) trait Calendar {
fn gomi_at(&self, time: DateTime<Local>) -> Vec<Gomi>;
}
83 changes: 83 additions & 0 deletions src/calendar/matsudo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
use crate::calendar::Calendar;
use crate::gomi::Gomi;

use chrono::{DateTime, Datelike, Local, Weekday, Weekday::*};

// Defines the gomi rules for Matsudo using a macro.
macro_rules! matsudo_rules {
(
$current_base: expr,
$current_time: expr,
// This repetition represents each rules based on the base day.
$((
$base: path,
($burnable1: path, $burnable2: path, $burnable3: path),
($glass_week_num: expr, $glass_week_day: path), // The Nth day of X
$recycle_plastic: path,
$other_plastic: path
)),*
$(,)?
) => {
// Matches the current base day for the location.
match ($current_base) {
$(
$base => (vec![
match ($current_time.weekday()) {
$base => Some(Gomi::new("資源ごみ")),
$burnable1 | $burnable2 | $burnable3 => Some(Gomi::new("燃やせるごみ")),
$recycle_plastic => Some(Gomi::new("リサイクルするプラスチック")),
$other_plastic => Some(Gomi::new("その他のプラスチックなどのごみ")),
_ => None,
},
if (week_num_by_weekday($current_time, $glass_week_day) == $glass_week_num) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

第何週目しか見てなくて陶磁器・ガラスなどのごみの週に全て「陶磁器・ガラスなどのゴミ」が入っちゃってそう

Some(Gomi::new("陶磁器・ガラスなどのごみ"))
} else {
None
}
]
// Converts Vec<Option<Gomi>> to Vec<Gomi>, remaining only Some elements.
.into_iter()
.flat_map(|x| x)
.collect()
)
),*,
// Ignores the unknown base day, returning an empty Vec.
_ => vec![],
}
}
}

pub(crate) struct Matsudo {
base: Weekday,
}

impl Matsudo {
pub(crate) fn new(base: Weekday) -> Self {
Self { base }
}
}

impl Calendar for Matsudo {
fn gomi_at(&self, time: DateTime<Local>) -> Vec<Gomi> {
// Using the defined rules, determines which Gomi's are available to take out.
matsudo_rules!(
self.base,
time,
(Mon, (Tue, Thu, Sat), (2, Thu), Wed, Fri),
(Tue, (Mon, Wed, Fri), (2, Wed), Thu, Sat),
(Wed, (Tue, Thu, Sat), (3, Thu), Fri, Mon),
(Thu, (Mon, Wed, Fri), (3, Wed), Sat, Tue),
(Fri, (Tue, Thu, Sat), (4, Thu), Mon, Wed),
(Sat, (Mon, Wed, Fri), (4, Wed), Tue, Thu),
)
}
}

fn week_num_by_weekday(time: DateTime<Local>, weekday: Weekday) -> u32 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

今日が月の第何週目を求めるなら、一年における経過した週から今月までに経過した週を引いた方がスッキリするかも


fn week_num_by_weekday2(time: Date<Local>) -> u32 {
    time.iso_week().week() - time.with_day0(0).unwrap().iso_week().week() + 1
}

#[cfg(test)]
mod tests {
    use chrono::{Local, TimeZone};
    use crate::calendar::matsudo::week_num_by_weekday2;

    #[test]
    fn week_num_3_17() {
        let date = Local.ymd(2021,3,17);
        assert_eq!(week_num_by_weekday2(date), 3);
    }
    #[test]
    fn week_num_1_1() {
        let date = Local.ymd(2021,1,1);
        assert_eq!(week_num_by_weekday2(date), 1);
    }


    #[test]
    fn week_num_12_31() {
        let date = Local.ymd(2021,12,31);
        assert_eq!(week_num_by_weekday2(date), 5);
    }

    #[test]
    fn week_num_2020_2_29() {
        let date = Local.ymd(2020,2,29);
        assert_eq!(week_num_by_weekday2(date), 5);
    }
}

time.day() / 7
+ if time.weekday().num_days_from_sunday() < weekday.num_days_from_sunday() {
0
} else {
1
}
}
19 changes: 19 additions & 0 deletions src/gomi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use std::fmt::{Display, Formatter, Result};

pub(crate) struct Gomi {
name: String,
}

impl Gomi {
pub(crate) fn new(name: &str) -> Self {
Self {
name: name.to_string(),
}
}
}

impl Display for Gomi {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(f, "{}", self.name)
}
}
20 changes: 19 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
pub(crate) mod calendar;
pub(crate) mod gomi;

use chrono::{Local, TimeZone, Weekday};

use crate::calendar::Calendar;

fn main() {
println!("Hello, world!");
let calendar = calendar::matsudo::Matsudo::new(Weekday::Thu);
let today = Local.ymd(2021, 3, 17).and_hms(0, 0, 0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

日付だけ見て処理するのであればDateTimeじゃなくてDateで処理した方がいいかも

let gomi = calendar.gomi_at(today);

println!(
"今日 {} は {} の日です",
today,
gomi.iter()
.map(|g| g.to_string())
.collect::<Vec<String>>()
.join(", ")
)
}