about summary refs log tree commit diff
path: root/src/ifc.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/ifc.rs')
-rw-r--r--src/ifc.rs112
1 files changed, 112 insertions, 0 deletions
diff --git a/src/ifc.rs b/src/ifc.rs
new file mode 100644
index 0000000..d0a9f5f
--- /dev/null
+++ b/src/ifc.rs
@@ -0,0 +1,112 @@
+//! The international fixed calendar is a 13-month calendar with each month
+//! containing exactly 28 days. There is an extra day at the end of the year
+//! called the year day.
+//!
+//! In leap-years there is an extra day inserted at the end of June called the
+//! leap day. It is directly after the fourth week of june and is given to june,
+//! so it becomes June 29th. The day after June 29th starts the new month, Sol,
+//! with Sol 1.
+//!
+//! [Wikipedia: International Fixed Calendar][wp-ifc]
+//! [wp-ifc]: https://en.wikipedia.org/wiki/International_Fixed_Calendar
+
+use time::Date as TimeDate;
+
+const MONTHS: [[&str; 2]; 13] = [
+	["January", "Jan"],
+	["February", "Feb"],
+	["March", "Mar"],
+	["April", "Apr"],
+	["May", "May"],
+	["June", "Jun"],
+	["Sol", "Sol"],
+	["July", "Jul"],
+	["August", "Aug"],
+	["September", "Sep"],
+	["October", "Oct"],
+	["November", "Nov"],
+	["December", "Dec"],
+];
+
+pub struct Calendar {
+	pub year: usize,
+	pub ordinal: usize,
+}
+
+impl Calendar {
+	pub fn from_year(year: usize) -> Self {
+		Self { year, ordinal: 0 }
+	}
+
+	pub fn from_time_date(date: TimeDate) -> Self {
+		let year = date.year() as usize;
+		let ord = date.ordinal() as usize;
+
+		Self { year, ordinal: ord }
+	}
+}
+
+pub struct Date {
+	pub year: u32,
+	pub month: u8,
+	pub day: u8,
+}
+
+impl Date {
+	pub fn from_time_date(date: TimeDate) -> Self {
+		let year = date.year() as u32;
+		let ord = date.ordinal();
+
+		if !year_leaps(year) || ord <= 168 {
+			// not a leap year path
+			// also the "leap year but before the leap-day" path
+			Self {
+				year,
+				month: (ord / 28) as u8,
+				day: (ord % 28) as u8,
+			}
+		} else if ord == 169 {
+			Self {
+				year,
+				month: 6,
+				day: 29,
+			}
+		} else {
+			todo!()
+		}
+	}
+
+	pub fn is_leap(&self) -> bool {
+		year_leaps(self.year)
+	}
+}
+
+/// Whether or not a year is a leap year
+fn year_leaps(year: u32) -> bool {
+	let four = year % 4 == 0;
+	let hundreds = year % 100 == 0;
+	let fourhund = year % 400 == 0;
+
+	// leap if:
+	// - four AND NOT hundred
+	// - four AND hundred AND fourhund
+
+	// `fourhund` here checks `hundreds` by virtue of 100 being a multiple of 400
+	four && (!hundreds || fourhund)
+}
+
+mod test {
+	use crate::ifc::year_leaps;
+
+	#[test]
+	fn leap_years() {
+		// the examples given by wikipedia
+		assert!(year_leaps(2000));
+		assert!(!year_leaps(1700));
+		assert!(!year_leaps(1800));
+		assert!(!year_leaps(1900));
+
+		// testing the four rule
+		assert!(year_leaps(2024));
+	}
+}