diff --git a/ifc/Cargo.lock b/ifc/Cargo.lock
index 2d31440..5e8465a 100644
--- a/ifc/Cargo.lock
+++ b/ifc/Cargo.lock
@@ -171,6 +171,7 @@ dependencies = [
"params",
"router",
"serde",
+ "thiserror",
]
[[package]]
@@ -816,6 +817,26 @@ dependencies = [
"remove_dir_all",
]
+[[package]]
+name = "thiserror"
+version = "1.0.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "time"
version = "0.1.44"
diff --git a/ifc/Cargo.toml b/ifc/Cargo.toml
index 9c3d902..a75b2ee 100644
--- a/ifc/Cargo.toml
+++ b/ifc/Cargo.toml
@@ -10,18 +10,19 @@ license = "GPL-3.0-only"
license-file = "../COPYING"
[dependencies]
-chrono = "0.4"
-chrono-tz = "0.6"
-iron = "0.6.1"
-mustache = "0.9.0"
-params = "*"
-router = "*"
-serde = { version = "1.0", features = ["derive"] }
+chrono = { version = "0.4" }
+chrono-tz = { version = "0.6" }
+iron = { version = "0.6.1" }
+mustache = { version = "0.9.0" }
+params = { version = "*" }
+router = { version = "*" }
+serde = { version = "1.0", features = ["derive"] }
+thiserror = { version = "1" }
-[[bin]]
-name = "ifc-today"
-path = "src/today.rs"
+# [[bin]]
+# name = "ifc-today"
+# path = "src/today.rs"
-[[bin]]
-name = "ifc-web"
-path = "src/web.rs"
+# [[bin]]
+# name = "ifc-web"
+# path = "src/web.rs"
diff --git a/ifc/src/lib.rs b/ifc/src/lib.rs
index d807833..30db983 100644
--- a/ifc/src/lib.rs
+++ b/ifc/src/lib.rs
@@ -10,10 +10,15 @@ Luminescent Dreams Tools is distributed in the hope that it will be useful, but
You should have received a copy of the GNU General Public License along with Lumeto. If not, see .
*/
-extern crate chrono;
-extern crate chrono_tz;
-
use chrono::{Datelike, NaiveDate};
+use serde::{Deserialize, Serialize};
+use thiserror::Error;
+
+#[derive(Clone, Debug, Error, PartialEq)]
+pub enum Error {
+ #[error("invalid date")]
+ InvalidDate,
+}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum DayOfWeek {
@@ -104,6 +109,110 @@ impl From for String {
}
}
+fn is_leap_year(year: i32) -> bool {
+ NaiveDate::from_ymd(year, 12, 31).ordinal() == 366
+}
+
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+pub enum IFC {
+ LeapDay(i32),
+ YearDay(i32),
+ Day(Day),
+}
+
+impl IFC {
+ fn leap_day(year: i32) -> Result {
+ if is_leap_year(year) {
+ Ok(Self::LeapDay(year))
+ } else {
+ Err(Error::InvalidDate)
+ }
+ }
+
+ fn year_day(year: i32) -> Self {
+ Self::YearDay(year)
+ }
+
+ fn ymd(year: i32, month: u8, day: u8) -> Result {
+ if month < 1 || month > 13 {
+ Err(Error::InvalidDate)
+ } else if day < 1 || day > 28 {
+ Err(Error::InvalidDate)
+ } else {
+ Ok(Self::Day(Day { year, month, day }))
+ }
+ }
+
+ fn day_of_week(&self) -> DayOfWeek {
+ match *self {
+ IFC::LeapDay(_) => DayOfWeek::LeapDay,
+ IFC::YearDay(_) => DayOfWeek::YearDay,
+ IFC::Day(Day { day, .. }) => match (day - 1) % 7 {
+ 0 => DayOfWeek::Sunday,
+ 1 => DayOfWeek::Monday,
+ 2 => DayOfWeek::Tuesday,
+ 3 => DayOfWeek::Wednesday,
+ 4 => DayOfWeek::Thursday,
+ 5 => DayOfWeek::Friday,
+ 6 => DayOfWeek::Saturday,
+ _ => panic!("impossible calculation"),
+ },
+ }
+ }
+
+ fn day_ordinal(&self) -> u32 {
+ self.day_ordinal0() + 1
+ }
+
+ fn day_ordinal0(&self) -> u32 {
+ match *self {
+ IFC::LeapDay(_) => 168,
+ IFC::YearDay(year) => {
+ if is_leap_year(year) {
+ 365
+ } else {
+ 364
+ }
+ }
+ IFC::Day(Day { year, month, day }) => {
+ u32::from(month - 1) * 28
+ + u32::from(day - 1)
+ + if is_leap_year(year) && month > 6 {
+ 1
+ } else {
+ 0
+ }
+ }
+ }
+ }
+
+ fn week_ordinal(&self) -> u32 {
+ self.week_ordinal0() + 1
+ }
+
+ fn week_ordinal0(&self) -> u32 {
+ match *self {
+ IFC::LeapDay(_) => 0,
+ IFC::YearDay(_) => 0,
+ IFC::Day(Day { month, day, .. }) => u32::from(month - 1) * 4 + (u32::from(day - 1) / 7),
+ }
+ }
+}
+
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+pub struct Day {
+ year: i32,
+ month: u8,
+ day: u8,
+}
+
+impl From for Day {
+ fn from(date: chrono::NaiveDate) -> Self {
+ unimplemented!();
+ }
+}
+
+/*
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct IFC {
year: u32,
@@ -111,12 +220,9 @@ pub struct IFC {
leap_year: bool,
}
-fn is_leap_year(year: i32) -> bool {
- NaiveDate::from_ymd(year, 12, 31).ordinal() == 366
-}
impl IFC {
- pub fn ymd(year: u32, month: u8, day: u8) -> IFC {
+ pub fn ymd(year: u32, month: u8, day: u8) -> Self {
let leap_year = is_leap_year(year as i32 - 10000);
let ordinal = if is_leap_year(year as i32 - 10000) {
@@ -138,7 +244,18 @@ impl IFC {
}
}
- pub fn weekday_ifc(&self) -> DayOfWeek {
+ pub fn year_day(year: u32) -> Self {
+ Self {
+ year,
+ ordinal: if is_leap_year(year) { 366 } else { 365 }
+ }
+ }
+
+ pub fn leap_day(year: u32) -> Result {
+ }
+
+ pub fn weekday(&self) -> DayOfWeek {
+ // if self.day.ordinal ==
match self.day() % 7 {
0 => DayOfWeek::Saturday,
1 => DayOfWeek::Sunday,
@@ -155,7 +272,9 @@ impl IFC {
Month::from(self.month())
}
}
+*/
+/*
impl From> for IFC {
fn from(d: chrono::Date) -> IFC {
IFC::from(d.naive_utc())
@@ -178,7 +297,9 @@ impl From for IFC {
}
}
}
+*/
+/*
impl Datelike for IFC {
fn year(&self) -> i32 {
self.year as i32
@@ -276,6 +397,7 @@ impl Datelike for IFC {
})
}
}
+*/
#[cfg(test)]
mod tests {
@@ -283,6 +405,188 @@ mod tests {
use chrono::NaiveDate;
+ #[test]
+ fn creates_a_day() {
+ assert_eq!(IFC::leap_day(12020), Ok(IFC::LeapDay(12020)));
+ assert_eq!(IFC::year_day(12020), IFC::YearDay(12020));
+ assert_eq!(
+ IFC::ymd(12022, 13, 28),
+ Ok(IFC::Day(Day {
+ year: 12022,
+ month: 13,
+ day: 28
+ }))
+ );
+ }
+
+ #[test]
+ fn rejects_invalid_dates() {
+ assert_eq!(IFC::leap_day(12022), Err(Error::InvalidDate));
+ assert_eq!(IFC::ymd(12022, 13, 0), Err(Error::InvalidDate));
+ assert_eq!(IFC::ymd(12022, 14, 1), Err(Error::InvalidDate));
+ }
+
+ #[test]
+ fn it_expresses_day_of_week() {
+ assert_eq!(
+ IFC::leap_day(12020).unwrap().day_of_week(),
+ DayOfWeek::LeapDay
+ );
+ assert_eq!(IFC::year_day(12022).day_of_week(), DayOfWeek::YearDay);
+ assert_eq!(
+ IFC::ymd(12022, 1, 1).unwrap().day_of_week(),
+ DayOfWeek::Sunday
+ );
+ assert_eq!(
+ IFC::ymd(12022, 1, 2).unwrap().day_of_week(),
+ DayOfWeek::Monday
+ );
+ assert_eq!(
+ IFC::ymd(12022, 1, 3).unwrap().day_of_week(),
+ DayOfWeek::Tuesday
+ );
+ assert_eq!(
+ IFC::ymd(12022, 1, 4).unwrap().day_of_week(),
+ DayOfWeek::Wednesday
+ );
+ assert_eq!(
+ IFC::ymd(12022, 1, 5).unwrap().day_of_week(),
+ DayOfWeek::Thursday
+ );
+ assert_eq!(
+ IFC::ymd(12022, 1, 6).unwrap().day_of_week(),
+ DayOfWeek::Friday
+ );
+ assert_eq!(
+ IFC::ymd(12022, 1, 7).unwrap().day_of_week(),
+ DayOfWeek::Saturday
+ );
+ assert_eq!(
+ IFC::ymd(12022, 1, 8).unwrap().day_of_week(),
+ DayOfWeek::Sunday
+ );
+ }
+
+ #[test]
+ fn it_reports_ordinal_days() {
+ assert_eq!(IFC::ymd(12022, 1, 1).unwrap().day_ordinal(), 1);
+ assert_eq!(IFC::ymd(12022, 1, 1).unwrap().day_ordinal0(), 0);
+
+ assert_eq!(IFC::ymd(12022, 1, 28).unwrap().day_ordinal(), 28);
+ assert_eq!(IFC::ymd(12022, 1, 28).unwrap().day_ordinal0(), 27);
+
+ assert_eq!(IFC::ymd(12022, 2, 1).unwrap().day_ordinal(), 29);
+ assert_eq!(IFC::ymd(12022, 2, 1).unwrap().day_ordinal0(), 28);
+
+ assert_eq!(IFC::ymd(12022, 3, 1).unwrap().day_ordinal(), 57);
+ assert_eq!(IFC::ymd(12022, 3, 1).unwrap().day_ordinal0(), 56);
+
+ assert_eq!(IFC::ymd(12022, 4, 1).unwrap().day_ordinal(), 85);
+ assert_eq!(IFC::ymd(12022, 4, 1).unwrap().day_ordinal0(), 84);
+
+ assert_eq!(IFC::ymd(12022, 5, 1).unwrap().day_ordinal(), 113);
+ assert_eq!(IFC::ymd(12022, 5, 1).unwrap().day_ordinal0(), 112);
+
+ assert_eq!(IFC::ymd(12022, 6, 1).unwrap().day_ordinal(), 141);
+ assert_eq!(IFC::ymd(12022, 6, 1).unwrap().day_ordinal0(), 140);
+
+ assert_eq!(IFC::ymd(12022, 7, 1).unwrap().day_ordinal(), 169);
+ assert_eq!(IFC::ymd(12022, 7, 1).unwrap().day_ordinal0(), 168);
+
+ assert_eq!(IFC::ymd(12022, 8, 1).unwrap().day_ordinal(), 197);
+ assert_eq!(IFC::ymd(12022, 8, 1).unwrap().day_ordinal0(), 196);
+
+ assert_eq!(IFC::ymd(12022, 9, 1).unwrap().day_ordinal(), 225);
+ assert_eq!(IFC::ymd(12022, 9, 1).unwrap().day_ordinal0(), 224);
+
+ assert_eq!(IFC::ymd(12022, 10, 1).unwrap().day_ordinal(), 253);
+ assert_eq!(IFC::ymd(12022, 10, 1).unwrap().day_ordinal0(), 252);
+
+ assert_eq!(IFC::ymd(12022, 11, 1).unwrap().day_ordinal(), 281);
+ assert_eq!(IFC::ymd(12022, 11, 1).unwrap().day_ordinal0(), 280);
+
+ assert_eq!(IFC::ymd(12022, 12, 1).unwrap().day_ordinal(), 309);
+ assert_eq!(IFC::ymd(12022, 12, 1).unwrap().day_ordinal0(), 308);
+
+ assert_eq!(IFC::ymd(12022, 13, 1).unwrap().day_ordinal(), 337);
+ assert_eq!(IFC::ymd(12022, 13, 1).unwrap().day_ordinal0(), 336);
+
+ assert_eq!(IFC::ymd(12022, 13, 28).unwrap().day_ordinal(), 364);
+ assert_eq!(IFC::ymd(12022, 13, 28).unwrap().day_ordinal0(), 363);
+
+ assert_eq!(IFC::year_day(12022).day_ordinal(), 365);
+ }
+
+ #[test]
+ fn it_reports_ordinal_days_on_leap_year() {
+ assert_eq!(IFC::ymd(12020, 1, 1).unwrap().day_ordinal(), 1);
+ assert_eq!(IFC::ymd(12020, 1, 1).unwrap().day_ordinal0(), 0);
+
+ assert_eq!(IFC::ymd(12020, 1, 28).unwrap().day_ordinal(), 28);
+ assert_eq!(IFC::ymd(12020, 1, 28).unwrap().day_ordinal0(), 27);
+
+ assert_eq!(IFC::ymd(12020, 2, 1).unwrap().day_ordinal(), 29);
+ assert_eq!(IFC::ymd(12020, 2, 1).unwrap().day_ordinal0(), 28);
+
+ assert_eq!(IFC::ymd(12020, 3, 1).unwrap().day_ordinal(), 57);
+ assert_eq!(IFC::ymd(12020, 3, 1).unwrap().day_ordinal0(), 56);
+
+ assert_eq!(IFC::ymd(12020, 4, 1).unwrap().day_ordinal(), 85);
+ assert_eq!(IFC::ymd(12020, 4, 1).unwrap().day_ordinal0(), 84);
+
+ assert_eq!(IFC::ymd(12020, 5, 1).unwrap().day_ordinal(), 113);
+ assert_eq!(IFC::ymd(12020, 5, 1).unwrap().day_ordinal0(), 112);
+
+ assert_eq!(IFC::ymd(12020, 6, 1).unwrap().day_ordinal(), 141);
+ assert_eq!(IFC::ymd(12020, 6, 1).unwrap().day_ordinal0(), 140);
+
+ assert_eq!(IFC::leap_day(12020).unwrap().day_ordinal(), 169);
+ assert_eq!(IFC::leap_day(12020).unwrap().day_ordinal0(), 168);
+
+ assert_eq!(IFC::ymd(12020, 7, 1).unwrap().day_ordinal(), 170);
+ assert_eq!(IFC::ymd(12020, 7, 1).unwrap().day_ordinal0(), 169);
+
+ assert_eq!(IFC::ymd(12020, 8, 1).unwrap().day_ordinal(), 198);
+ assert_eq!(IFC::ymd(12020, 8, 1).unwrap().day_ordinal0(), 197);
+
+ assert_eq!(IFC::ymd(12020, 9, 1).unwrap().day_ordinal(), 226);
+ assert_eq!(IFC::ymd(12020, 9, 1).unwrap().day_ordinal0(), 225);
+
+ assert_eq!(IFC::ymd(12020, 10, 1).unwrap().day_ordinal(), 254);
+ assert_eq!(IFC::ymd(12020, 10, 1).unwrap().day_ordinal0(), 253);
+
+ assert_eq!(IFC::ymd(12020, 11, 1).unwrap().day_ordinal(), 282);
+ assert_eq!(IFC::ymd(12020, 11, 1).unwrap().day_ordinal0(), 281);
+
+ assert_eq!(IFC::ymd(12020, 12, 1).unwrap().day_ordinal(), 310);
+ assert_eq!(IFC::ymd(12020, 12, 1).unwrap().day_ordinal0(), 309);
+
+ assert_eq!(IFC::ymd(12020, 13, 1).unwrap().day_ordinal(), 338);
+ assert_eq!(IFC::ymd(12020, 13, 1).unwrap().day_ordinal0(), 337);
+
+ assert_eq!(IFC::ymd(12020, 13, 28).unwrap().day_ordinal(), 365);
+ assert_eq!(IFC::ymd(12020, 13, 28).unwrap().day_ordinal0(), 364);
+
+ assert_eq!(IFC::year_day(12020).day_ordinal(), 366);
+ }
+
+ #[test]
+ fn it_reports_ordinal_weeks() {
+ assert_eq!(IFC::ymd(12022, 1, 1).unwrap().week_ordinal(), 1);
+ assert_eq!(IFC::ymd(12022, 1, 1).unwrap().week_ordinal0(), 0);
+ assert_eq!(IFC::ymd(12022, 1, 4).unwrap().week_ordinal(), 1);
+ assert_eq!(IFC::ymd(12022, 1, 4).unwrap().week_ordinal0(), 0);
+ assert_eq!(IFC::ymd(12022, 1, 7).unwrap().week_ordinal(), 1);
+ assert_eq!(IFC::ymd(12022, 1, 7).unwrap().week_ordinal0(), 0);
+ assert_eq!(IFC::ymd(12022, 1, 8).unwrap().week_ordinal(), 2);
+ assert_eq!(IFC::ymd(12022, 1, 8).unwrap().week_ordinal0(), 1);
+ assert_eq!(IFC::ymd(12022, 2, 1).unwrap().week_ordinal(), 5);
+ assert_eq!(IFC::ymd(12022, 2, 1).unwrap().week_ordinal0(), 4);
+ assert_eq!(IFC::ymd(12022, 13, 28).unwrap().week_ordinal(), 52);
+ assert_eq!(IFC::ymd(12022, 13, 28).unwrap().week_ordinal0(), 51);
+ }
+
+ /*
#[test]
fn check_start_of_month() {
assert_eq!(
@@ -391,6 +695,9 @@ mod tests {
);
}
+ #[test]
+ fn report_leap_day() {}
+
#[test]
fn check_start_of_month_leap_year() {
assert_eq!(
@@ -663,20 +970,25 @@ mod tests {
assert_eq!(IFC::ymd(12019, 13, 29).day(), 29);
assert_eq!(IFC::ymd(12019, 13, 29).day0(), 28);
}
+ */
+ /*
#[test]
fn it_reports_correct_day_of_week() {
- assert_eq!(IFC::ymd(12019, 1, 1).weekday(), chrono::Weekday::Sun);
- assert_eq!(IFC::ymd(12019, 6, 1).weekday(), chrono::Weekday::Sun);
- assert_eq!(IFC::ymd(12019, 6, 28).weekday(), chrono::Weekday::Sat);
- assert_eq!(IFC::ymd(12019, 7, 1).weekday(), chrono::Weekday::Sun);
- assert_eq!(IFC::ymd(12019, 13, 28).weekday(), chrono::Weekday::Sat);
- assert_eq!(IFC::ymd(12019, 13, 29).weekday(), chrono::Weekday::Sat);
+ assert_eq!(IFC::ymd(12019, 1, 1).weekday(), DayOfWeek::Sunday);
+ assert_eq!(IFC::ymd(12019, 6, 1).weekday(), DayOfWeek::Sunday);
+ assert_eq!(IFC::ymd(12019, 6, 28).weekday(), DayOfWeek::Saturday);
+ assert_eq!(IFC::ymd(12019, 7, 1).weekday(), DayOfWeek::Sunday);
+ assert_eq!(IFC::ymd(12019, 13, 28).weekday(), DayOfWeek::Saturday);
+ assert_eq!(IFC::ymd(12019, 13, 29).weekday(), DayOfWeek::Saturday);
- assert_eq!(IFC::ymd(12020, 6, 28).weekday(), chrono::Weekday::Sat);
- assert_eq!(IFC::ymd(12020, 6, 29).weekday(), chrono::Weekday::Sat);
- assert_eq!(IFC::ymd(12020, 7, 1).weekday(), chrono::Weekday::Sun);
- assert_eq!(IFC::ymd(12020, 13, 28).weekday(), chrono::Weekday::Sat);
- assert_eq!(IFC::ymd(12020, 13, 29).weekday(), chrono::Weekday::Sat);
+ assert_eq!(IFC::ymd(12020, 6, 28).weekday(), DayOfWeek::Saturday);
+ assert_eq!(IFC::ymd(12020, 6, 29).weekday(), DayOfWeek::Saturday);
+ assert_eq!(IFC::ymd(12020, 7, 1).weekday(), DayOfWeek::Sunday);
+ assert_eq!(IFC::ymd(12020, 13, 28).weekday(), DayOfWeek::Saturday);
+ assert_eq!(IFC::ymd(12020, 13, 29).weekday(), DayOfWeek::Saturday);
+
+ assert_eq!(IFC::ymd(12022, 13, 31)
}
+ */
}