use crate::time::{date::Date, daycounters::daycount::DayCount};
pub struct Thirty360;
impl DayCount for Thirty360 {
fn day_count(start: Date, end: Date) -> i64 {
let d1 = i64::from(start.day());
let d2 = i64::from(end.day());
let m1 = i64::from(start.month());
let m2 = i64::from(end.month());
let y1 = i64::from(start.year());
let y2 = i64::from(end.year());
let dd1 = if d1 == 31 { 30 } else { d1 };
let dd2 = if d2 == 31 && dd1 == 30 { 30 } else { d2 };
360 * (y2 - y1) + 30 * (m2 - m1) + (dd2 - dd1)
}
fn year_fraction(start: Date, end: Date) -> f64 {
let days = i32::try_from(Self::day_count(start, end))
.unwrap_or_else(|_| panic!("day count should fit in i32"));
f64::from(days) / 360.0
}
}
pub struct Thirty360US;
const fn is_last_of_february(d: i64, m: i64, y: i32) -> bool {
if Date::is_leap_year(y) {
m == 2 && d == 28 + 1
} else {
m == 2 && d == 28
}
}
impl DayCount for Thirty360US {
fn day_count(start: Date, end: Date) -> i64 {
let d1 = i64::from(start.day());
let d2 = i64::from(end.day());
let m1 = i64::from(start.month());
let m2 = i64::from(end.month());
let y1 = start.year();
let y2 = end.year();
let dd1 = if d1 == 31 { 30 } else { d1 };
let dd2 = if d2 == 31 && dd1 >= 30 { 30 } else { d2 };
let dd1 = if is_last_of_february(dd1, m1, y1) {
30
} else {
dd1
};
let dd2 = if is_last_of_february(dd2, m2, y2) {
30
} else {
dd2
};
360 * (i64::from(y2) - i64::from(y1)) + 30 * (m2 - m1) + (dd2 - dd1)
}
fn year_fraction(start: Date, end: Date) -> f64 {
let days = i32::try_from(Self::day_count(start, end))
.unwrap_or_else(|_| panic!("day count should fit in i32"));
f64::from(days) / 360.0
}
}