/* Copyright 2020-2023, Savanni D'Gerinel This file is part of the Luminescent Dreams Tools. Luminescent Dreams Tools is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Luminescent Dreams Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Lumeto. If not, see . */ use chrono::{Datelike, NaiveDate}; use serde::{Deserialize, Serialize}; use std::convert::TryInto; 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 { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, LeapDay, YearDay, } impl From for String { fn from(day: DayOfWeek) -> Self { match day { DayOfWeek::Sunday => "Sunday", DayOfWeek::Monday => "Monday", DayOfWeek::Tuesday => "Tuesday", DayOfWeek::Wednesday => "Wednesday", DayOfWeek::Thursday => "Thursday", DayOfWeek::Friday => "Friday", DayOfWeek::Saturday => "Saturday", DayOfWeek::LeapDay => "LeapDay", DayOfWeek::YearDay => "YearDay", } .to_owned() } } #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum Month { January, February, March, April, May, June, Sol, July, August, September, October, November, December, } impl From for Month { fn from(val: u32) -> Month { match val { 1 => Month::January, 2 => Month::February, 3 => Month::March, 4 => Month::April, 5 => Month::May, 6 => Month::June, 7 => Month::Sol, 8 => Month::July, 9 => Month::August, 10 => Month::September, 11 => Month::October, 12 => Month::November, 13 => Month::December, _ => panic!("invalid month number"), } } } impl From for String { fn from(val: Month) -> String { match val { Month::January => "January", Month::February => "February", Month::March => "March", Month::April => "April", Month::May => "May", Month::June => "June", Month::Sol => "Sol", Month::July => "July", Month::August => "August", Month::September => "September", Month::October => "October", Month::November => "November", Month::December => "December", } .to_owned() } } fn is_leap_year(year: i32) -> bool { NaiveDate::from_ymd_opt(year, 12, 31).unwrap().ordinal() == 366 } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum IFC { LeapDay(i32), YearDay(i32), Day(Day), } impl IFC { pub fn leap_day(year: i32) -> Result { if is_leap_year(year) { Ok(Self::LeapDay(year)) } else { Err(Error::InvalidDate) } } pub fn year_day(year: i32) -> Self { Self::YearDay(year) } pub 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 })) } } pub fn year(&self) -> i32 { match *self { IFC::LeapDay(year) => year, IFC::YearDay(year) => year, IFC::Day(Day { year, .. }) => year, } } pub fn month_ifc(&self) -> Month { Month::from(self.month()) } pub fn weekday_ifc(&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"), }, } } pub fn day_ordinal(&self) -> u32 { self.day_ordinal0() + 1 } pub 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 } } } } pub fn week_ordinal(&self) -> u32 { self.week_ordinal0() + 1 } pub 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 IFC { fn from(date: chrono::NaiveDate) -> Self { if date.month() == 12 && date.day() == 31 { Self::YearDay(date.year()) } else if is_leap_year(date.year()) && date.month() == 6 && date.day() == 17 { Self::LeapDay(date.year()) } else { let mut days = date.ordinal(); if is_leap_year(date.year()) && date > NaiveDate::from_ymd_opt(date.year(), 6, 17).unwrap() { days = days - 1; } let month: u8 = (days / 28).try_into().unwrap(); let day: u8 = (days % 28).try_into().unwrap(); Self::Day(Day { year: date.year(), month: month + 1, day, }) } } } impl From for chrono::NaiveDate { fn from(ifc: IFC) -> Self { Self::from_ymd_opt(ifc.year(), 1, 1).unwrap() + chrono::naive::Days::new(ifc.day_ordinal0().into()) } } /* impl IFC { pub fn year_day(year: u32) -> Self { Self { year, ordinal: if is_leap_year(year) { 366 } else { 365 } } } } */ /* impl From> for IFC { fn from(d: chrono::Date) -> IFC { IFC::from(d.naive_utc()) } } impl From> for IFC { fn from(d: chrono::Date) -> IFC { IFC::from(d.naive_utc()) } } impl From for IFC { fn from(d: NaiveDate) -> IFC { //println!("d: {} [{}]", d.format("%Y-%m-%d"), d.ordinal()); IFC { year: (d.year() + 10000) as u32, ordinal: d.ordinal0(), leap_year: is_leap_year(d.year()), } } } */ impl Datelike for IFC { fn year(&self) -> i32 { // self.year as i32 unimplemented!() } fn month(&self) -> u32 { // self.month0() + 1 unimplemented!() } fn month0(&self) -> u32 { /* if self.leap_year && self.ordinal == 365 { 12 } else if self.leap_year && self.ordinal == 168 { 5 } else { self.ordinal / 28 } */ unimplemented!() } fn day(&self) -> u32 { // self.day0() + 1 unimplemented!() } fn day0(&self) -> u32 { /* if self.leap_year { if self.ordinal == 365 { 28 } else if self.ordinal == 168 { 28 } else if self.ordinal > 168 { (self.ordinal - 1).rem_euclid(28) as u32 } else { self.ordinal.rem_euclid(28) as u32 } } else { if self.ordinal == 364 { 28 } else { self.ordinal.rem_euclid(28) as u32 } } */ unimplemented!() } fn ordinal(&self) -> u32 { // self.ordinal + 1 unimplemented!() } fn ordinal0(&self) -> u32 { // self.ordinal unimplemented!() } fn weekday(&self) -> chrono::Weekday { if self.day0() == 28 { chrono::Weekday::Sat } else { match self.day0().rem_euclid(7) { 0 => chrono::Weekday::Sun, 1 => chrono::Weekday::Mon, 2 => chrono::Weekday::Tue, 3 => chrono::Weekday::Wed, 4 => chrono::Weekday::Thu, 5 => chrono::Weekday::Fri, 6 => chrono::Weekday::Sat, _ => panic!("rem_euclid should not return anything outside the 0..6 range"), } } } fn iso_week(&self) -> chrono::IsoWeek { panic!("iso_week is not implemented because chrono does not expose any constructors for IsoWeek!"); } fn with_year(&self, year: i32) -> Option { /* Some(IFC { year: (year as u32) + 10000, ordinal: self.ordinal, leap_year: is_leap_year(year), }) */ unimplemented!() } fn with_month(&self, month: u32) -> Option { // Some(IFC::ymd(self.year, month as u8, self.day() as u8)) unimplemented!() } fn with_month0(&self, month: u32) -> Option { // Some(IFC::ymd(self.year, month as u8 + 1, self.day() as u8)) unimplemented!() } fn with_day(&self, day: u32) -> Option { // Some(IFC::ymd(self.year, self.month() as u8, day as u8)) unimplemented!() } fn with_day0(&self, day: u32) -> Option { // Some(IFC::ymd(self.year, self.month() as u8, day as u8 + 1)) unimplemented!() } fn with_ordinal(&self, ordinal: u32) -> Option { /* Some(IFC { year: self.year, ordinal, leap_year: self.leap_year, }) */ unimplemented!() } fn with_ordinal0(&self, ordinal: u32) -> Option { /* Some(IFC { year: self.year, ordinal: ordinal + 1, leap_year: self.leap_year, }) */ unimplemented!() } } #[cfg(test)] mod tests { use super::*; 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().weekday_ifc(), DayOfWeek::LeapDay ); assert_eq!(IFC::year_day(12022).weekday_ifc(), DayOfWeek::YearDay); assert_eq!( IFC::ymd(12022, 1, 1).unwrap().weekday_ifc(), DayOfWeek::Sunday ); assert_eq!( IFC::ymd(12022, 1, 2).unwrap().weekday_ifc(), DayOfWeek::Monday ); assert_eq!( IFC::ymd(12022, 1, 3).unwrap().weekday_ifc(), DayOfWeek::Tuesday ); assert_eq!( IFC::ymd(12022, 1, 4).unwrap().weekday_ifc(), DayOfWeek::Wednesday ); assert_eq!( IFC::ymd(12022, 1, 5).unwrap().weekday_ifc(), DayOfWeek::Thursday ); assert_eq!( IFC::ymd(12022, 1, 6).unwrap().weekday_ifc(), DayOfWeek::Friday ); assert_eq!( IFC::ymd(12022, 1, 7).unwrap().weekday_ifc(), DayOfWeek::Saturday ); assert_eq!( IFC::ymd(12022, 1, 8).unwrap().weekday_ifc(), 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 it_converts_from_gregorian() { assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12022, 1, 1).unwrap()), IFC::ymd(12022, 1, 1).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12022, 1, 29).unwrap()), IFC::ymd(12022, 2, 1).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12022, 2, 26).unwrap()), IFC::ymd(12022, 3, 1).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12022, 3, 26).unwrap()), IFC::ymd(12022, 4, 1).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12022, 4, 23).unwrap()), IFC::ymd(12022, 5, 1).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12022, 5, 21).unwrap()), IFC::ymd(12022, 6, 1).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12022, 6, 18).unwrap()), IFC::ymd(12022, 7, 1).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12022, 7, 16).unwrap()), IFC::ymd(12022, 8, 1).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12022, 8, 13).unwrap()), IFC::ymd(12022, 9, 1).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12022, 9, 10).unwrap()), IFC::ymd(12022, 10, 1).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12022, 10, 8).unwrap()), IFC::ymd(12022, 11, 1).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12022, 11, 5).unwrap()), IFC::ymd(12022, 12, 1).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12022, 12, 3).unwrap()), IFC::ymd(12022, 13, 1).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12022, 12, 31).unwrap()), IFC::YearDay(12022) ); } #[test] fn it_converts_from_gregorian_on_leap_year() { assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12020, 1, 1).unwrap()), IFC::ymd(12020, 1, 1).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12020, 1, 29).unwrap()), IFC::ymd(12020, 2, 1).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12020, 2, 26).unwrap()), IFC::ymd(12020, 3, 1).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12020, 2, 28).unwrap()), IFC::ymd(12020, 3, 3).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12020, 2, 29).unwrap()), IFC::ymd(12020, 3, 4).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12020, 3, 1).unwrap()), IFC::ymd(12020, 3, 5).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12020, 3, 25).unwrap()), IFC::ymd(12020, 4, 1).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12020, 4, 22).unwrap()), IFC::ymd(12020, 5, 1).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12020, 5, 20).unwrap()), IFC::ymd(12020, 6, 1).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12020, 6, 17).unwrap()), IFC::LeapDay(12020) ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12020, 6, 18).unwrap()), IFC::ymd(12020, 7, 1).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12020, 7, 16).unwrap()), IFC::ymd(12020, 8, 1).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12020, 8, 13).unwrap()), IFC::ymd(12020, 9, 1).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12020, 9, 10).unwrap()), IFC::ymd(12020, 10, 1).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12020, 10, 8).unwrap()), IFC::ymd(12020, 11, 1).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12020, 11, 5).unwrap()), IFC::ymd(12020, 12, 1).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12020, 12, 3).unwrap()), IFC::ymd(12020, 13, 1).unwrap() ); assert_eq!( IFC::from(NaiveDate::from_ymd_opt(12020, 12, 31).unwrap()), IFC::YearDay(12020) ); } #[test] fn it_converts_to_gregorian() { assert_eq!( NaiveDate::from(IFC::ymd(12020, 1, 1).unwrap()), NaiveDate::from_ymd_opt(12020, 1, 1).unwrap() ); assert_eq!( NaiveDate::from(IFC::leap_day(12020).unwrap()), NaiveDate::from_ymd_opt(12020, 6, 17).unwrap() ); assert_eq!( NaiveDate::from(IFC::ymd(12020, 3, 4).unwrap()), NaiveDate::from_ymd_opt(12020, 2, 29).unwrap() ); assert_eq!( NaiveDate::from(IFC::year_day(12020)), NaiveDate::from_ymd_opt(12020, 12, 31).unwrap() ); } /* #[test] fn check_start_of_month() { assert_eq!( IFC::ymd(12019, 1, 1), IFC { year: 12019, ordinal: 0, leap_year: false } ); assert_eq!( IFC::ymd(12019, 2, 1), IFC { year: 12019, ordinal: 28, leap_year: false } ); assert_eq!( IFC::ymd(12019, 3, 1), IFC { year: 12019, ordinal: 56, leap_year: false } ); assert_eq!( IFC::ymd(12019, 4, 1), IFC { year: 12019, ordinal: 84, leap_year: false } ); assert_eq!( IFC::ymd(12019, 5, 1), IFC { year: 12019, ordinal: 112, leap_year: false } ); assert_eq!( IFC::ymd(12019, 6, 1), IFC { year: 12019, ordinal: 140, leap_year: false } ); assert_eq!( IFC::ymd(12019, 7, 1), IFC { year: 12019, ordinal: 168, leap_year: false } ); assert_eq!( IFC::ymd(12019, 8, 1), IFC { year: 12019, ordinal: 196, leap_year: false } ); assert_eq!( IFC::ymd(12019, 9, 1), IFC { year: 12019, ordinal: 224, leap_year: false } ); assert_eq!( IFC::ymd(12019, 10, 1), IFC { year: 12019, ordinal: 252, leap_year: false } ); assert_eq!( IFC::ymd(12019, 11, 1), IFC { year: 12019, ordinal: 280, leap_year: false } ); assert_eq!( IFC::ymd(12019, 12, 1), IFC { year: 12019, ordinal: 308, leap_year: false } ); assert_eq!( IFC::ymd(12019, 13, 1), IFC { year: 12019, ordinal: 336, leap_year: false } ); } #[test] fn report_leap_day() {} #[test] fn check_start_of_month_leap_year() { assert_eq!( IFC::ymd(12020, 1, 1), IFC { year: 12020, ordinal: 0, leap_year: true } ); assert_eq!( IFC::ymd(12020, 2, 1), IFC { year: 12020, ordinal: 28, leap_year: true } ); assert_eq!( IFC::ymd(12020, 3, 1), IFC { year: 12020, ordinal: 56, leap_year: true } ); assert_eq!( IFC::ymd(12020, 4, 1), IFC { year: 12020, ordinal: 84, leap_year: true } ); assert_eq!( IFC::ymd(12020, 5, 1), IFC { year: 12020, ordinal: 112, leap_year: true } ); assert_eq!( IFC::ymd(12020, 6, 1), IFC { year: 12020, ordinal: 140, leap_year: true } ); assert_eq!( IFC::ymd(12020, 6, 29), IFC { year: 12020, ordinal: 168, leap_year: true } ); assert_eq!( IFC::ymd(12020, 7, 1), IFC { year: 12020, ordinal: 169, leap_year: true } ); assert_eq!( IFC::ymd(12020, 8, 1), IFC { year: 12020, ordinal: 197, leap_year: true } ); assert_eq!( IFC::ymd(12020, 9, 1), IFC { year: 12020, ordinal: 225, leap_year: true } ); assert_eq!( IFC::ymd(12020, 10, 1), IFC { year: 12020, ordinal: 253, leap_year: true } ); assert_eq!( IFC::ymd(12020, 11, 1), IFC { year: 12020, ordinal: 281, leap_year: true } ); assert_eq!( IFC::ymd(12020, 12, 1), IFC { year: 12020, ordinal: 309, leap_year: true } ); assert_eq!( IFC::ymd(12020, 13, 1), IFC { year: 12020, ordinal: 337, leap_year: true } ); } #[test] fn it_matches_january_1() { assert_eq!( IFC::from(NaiveDate::from_ymd(2019, 1, 1)), IFC::ymd(12019, 1, 1) ); } #[test] fn it_matches_february_1() { assert_eq!( IFC::from(NaiveDate::from_ymd(2019, 1, 29)), IFC::ymd(12019, 2, 1) ); } #[test] fn it_matches_sol_1() { assert_eq!( IFC::from(NaiveDate::from_ymd(2019, 6, 18)), IFC::ymd(12019, 7, 1) ); } #[test] fn it_matches_year_day() { assert_eq!( IFC::from(NaiveDate::from_ymd(2019, 12, 31)), IFC::ymd(12019, 13, 29) ); } #[test] fn it_matches_leap_day() { assert_eq!( IFC::from(NaiveDate::from_ymd(2019, 6, 18)), IFC::ymd(12019, 7, 1), ); assert_eq!( IFC::from(NaiveDate::from_ymd(2020, 6, 17)), IFC::ymd(12020, 6, 29), ); assert_eq!( IFC::from(NaiveDate::from_ymd(2020, 6, 18)), IFC::ymd(12020, 7, 1), ); assert_ne!(IFC::ymd(12020, 6, 29), IFC::ymd(12020, 7, 1)); } #[test] fn it_handles_gregorian_leap_day() { assert_eq!( IFC::from(NaiveDate::from_ymd(2019, 3, 1)), IFC::ymd(12019, 3, 4) ); assert_eq!( IFC::from(NaiveDate::from_ymd(2020, 2, 29)), IFC::ymd(12020, 3, 4) ); } #[test] fn it_handles_days_between_leap_days() { assert_eq!( IFC::from(NaiveDate::from_ymd(2020, 4, 8)), IFC::ymd(12020, 4, 15), ); } #[test] fn it_handles_days_after_ifc_leap_day() { assert_eq!( IFC::from(NaiveDate::from_ymd(2020, 10, 8)), IFC::ymd(12020, 11, 1), ); } #[test] fn it_matches_year_day_in_leap_year() { assert_eq!(NaiveDate::from_ymd(2020, 12, 31).ordinal(), 366); assert_eq!( IFC::from(NaiveDate::from_ymd(2020, 12, 31)), IFC::ymd(12020, 13, 29) ); } #[test] fn it_reports_correct_month() { assert_eq!(IFC::ymd(12019, 1, 1).month(), 1); assert_eq!(IFC::ymd(12019, 1, 1).month0(), 0); assert_eq!(IFC::ymd(12020, 6, 28).month(), 6); assert_eq!(IFC::ymd(12020, 6, 28).month0(), 5); assert_eq!(IFC::ymd(12020, 7, 1).month(), 7); assert_eq!(IFC::ymd(12020, 7, 1).month0(), 6); assert_eq!(IFC::ymd(12019, 13, 1).month(), 13); assert_eq!(IFC::ymd(12019, 13, 1).month0(), 12); } #[test] fn it_reports_correct_day() { assert_eq!(IFC::ymd(12019, 1, 1).day(), 1); assert_eq!(IFC::ymd(12019, 1, 1).day0(), 0); assert_eq!(IFC::ymd(12020, 3, 1).day(), 1); assert_eq!(IFC::ymd(12020, 3, 1).day0(), 0); assert_eq!(IFC::ymd(12020, 6, 28).day(), 28); assert_eq!(IFC::ymd(12020, 6, 28).day0(), 27); assert_eq!(IFC::ymd(12020, 7, 1).day(), 1); assert_eq!(IFC::ymd(12020, 7, 1).day0(), 0); assert_eq!(IFC::ymd(12019, 13, 1).day(), 1); assert_eq!(IFC::ymd(12019, 13, 1).day0(), 0); assert_eq!(IFC::ymd(12019, 13, 29).day(), 29); assert_eq!(IFC::ymd(12019, 13, 29).day0(), 28); } #[test] fn it_reports_correct_month_in_leap_year() { assert_eq!(IFC::ymd(12020, 1, 1).month(), 1); assert_eq!(IFC::ymd(12020, 1, 1).month0(), 0); assert_eq!(IFC::ymd(12020, 3, 1).month(), 3); assert_eq!(IFC::ymd(12020, 3, 1).month0(), 2); assert_eq!(IFC::ymd(12020, 6, 29).month(), 6); assert_eq!(IFC::ymd(12020, 6, 29).month0(), 5); assert_eq!(IFC::ymd(12020, 7, 1).month(), 7); assert_eq!(IFC::ymd(12020, 7, 1).month0(), 6); } #[test] fn it_reports_correct_day_in_leap_year() { assert_eq!(IFC::ymd(12019, 1, 1).day(), 1); assert_eq!(IFC::ymd(12019, 1, 1).day0(), 0); assert_eq!(IFC::ymd(12020, 6, 28).day(), 28); assert_eq!(IFC::ymd(12020, 6, 28).day0(), 27); assert_eq!(IFC::ymd(12020, 6, 29).day(), 29); assert_eq!(IFC::ymd(12020, 6, 29).day0(), 28); assert_eq!(IFC::ymd(12020, 7, 1).day(), 1); assert_eq!(IFC::ymd(12020, 7, 1).day0(), 0); assert_eq!(IFC::ymd(12019, 13, 1).day(), 1); assert_eq!(IFC::ymd(12019, 13, 1).day0(), 0); 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(), 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(), 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) } */ }