use jiff::civil;
pub fn dcos(deg: f32) -> f32 {
deg.to_radians().cos()
}
pub fn dsin(deg: f32) -> f32 {
deg.to_radians().sin()
}
pub fn equation_of_time(julian_date: f32) -> f32 {
let n = julian_date - 2_451_544.5;
let g = 0.985_600_3_f32.mul_add(n, 357.528);
let c = 0.0003_f32.mul_add(
dsin(3.0 * g),
1.9148_f32.mul_add(dsin(g), 0.02 * dsin(2.0 * g)),
);
let lambda = 0.985_600_3_f32.mul_add(n, 280.47) + c;
let r = 0.0014_f32.mul_add(
dsin(6.0 * lambda),
(-2.468_f32).mul_add(dsin(2.0 * lambda), 0.053 * dsin(4.0 * lambda)),
);
(c + r) * 4.0
}
pub fn hijri_to_julian(date: civil::Date) -> i32 {
let year = i32::from(date.year());
let month = i32::from(date.month());
let day = i32::from(date.day());
((11 * year + 3) / 30) + (354 * year) + (30 * month) - ((month - 1) / 2) + day + 1_948_440 - 385
}
pub fn gregorian_to_julian(date: civil::Date) -> f32 {
let (day, mut month, mut year) = (date.day(), date.month() as u8, date.year());
if month <= 2 {
month += 12;
year -= 1;
}
let a = (year as f32 / 100.0).floor() as i32;
let b = if year > 1582 || year == 1582 && month > 10 || month == 10 && day > 15 {
2 - a + (a / 4)
} else {
0
};
((365.25 * (year + 4716) as f32).floor() as i32
+ (30.6 * (month + 1) as f32).floor() as i32
+ day as i32
+ b) as f32
- 1524.5
}
pub fn julian_to_hijri(julian_date: i32, correction_val: i32) -> civil::Date {
let mut l = ((julian_date as f32 + correction_val as f32).floor() as i32 - 1_948_440) + 10632;
let n = (((l - 1) / 10631) as f32).floor();
l = l - (10631_f32 * n) as i32 + 354;
let j = (((10985 - l) / 5316) as f32).floor().mul_add(
(((50 * l) / 17719) as f32).floor(),
((l / 5670) as f32).floor() * (((43 * l) / 15238) as f32).floor(),
);
l = l
- (((30 - j as i32) / 15) as f32).floor() as i32
* (((17719 * j as i32) / 50) as f32).floor() as i32
- ((j as i32 / 16) as f32).floor() as i32
* (((15238 * j as i32) / 43) as f32).floor() as i32
+ 29;
let month = (((24 * l) / 709) as f32).floor();
let day = ((l - ((709_f32 * month) as i32 / 24)) as f32).floor();
let year = ((30_f32.mul_add(n, j) as i32 - 30) as f32).floor();
civil::date(year as i16, month as i8, day as i8)
}
pub fn julian_to_gregorian(mut julian_date: f32) -> civil::Date {
julian_date = (julian_date as i32 + 5) as f32;
let z = julian_date.floor() as i32;
let f = julian_date as i32 - z;
let a = if z < 2_299_161 {
z
} else {
let alpha = ((z as f32 - 1_867_216.25) / 36524.25).floor();
((z + 1) + alpha as i32) - ((alpha as i32 / 4) as f32).floor() as i32
};
let b = a + 1524;
let c = ((b as f32 - 122.1) / 365.25).floor();
let d = (365.25 * c).floor();
let e = ((b - d as i32) as f32 / 30.6001).floor();
let day = (b - d as i32) - (30.6001 * e).floor() as i32 + f;
let month = e as i32 - if (e as i32) < 14 { 1 } else { 13 };
let year = c as i32 - if month > 2 { 4716 } else { 4715 };
civil::date(year as i16, month as i8, day as i8)
}
#[cfg(test)]
mod tests {
use jiff::civil;
use super::*;
#[test]
fn test_dcos() {
assert_eq!(dcos(10.0), 0.9848077);
assert_eq!(dcos(20.0), 0.9396926);
assert_eq!(dcos(30.0), 0.8660254);
}
#[test]
fn test_dsin() {
assert_eq!(dsin(10.0), 0.17364818);
assert_eq!(dsin(20.0), 0.34202012);
assert_eq!(dsin(30.0), 0.5);
}
#[test]
fn test_equation_of_time() {
let precision = 5;
assert_eq!(equation_of_time(2_436_116.31), -11.653772);
assert_eq!(equation_of_time(1842713.0), 12.964235);
let equation = equation_of_time(2451545.0);
assert_eq!(format!("{:.1$}", equation, precision), "3.53552");
}
#[test]
fn test_hijri_to_julian() -> Result<(), crate::Error> {
assert_eq!(hijri_to_julian(civil::date(1442, 8, 25)), 2459313);
assert_eq!(hijri_to_julian(civil::date(333, 1, 27)), 2066116);
assert_eq!(hijri_to_julian(civil::date(1, 1, 27)), 1948466);
Ok(())
}
#[test]
fn test_georgian_to_julian() -> Result<(), crate::Error> {
assert_eq!(
gregorian_to_julian(civil::date(1957, 10, 4)),
2436115.5 );
assert_eq!(
gregorian_to_julian(civil::date(333, 1, 27)),
1842712.5 );
assert_eq!(
gregorian_to_julian(civil::date(2000, 1, 1)),
2451544.5 );
Ok(())
}
#[test]
fn test_julian_to_hijri() {
assert_eq!(julian_to_hijri(2459313, 0), civil::date(1442, 8, 25));
assert_eq!(julian_to_hijri(2066116, 0), civil::date(333, 1, 27));
assert_eq!(julian_to_hijri(1948466, 0), civil::date(1, 1, 27));
}
#[test]
fn test_julian_to_gregorian() {
assert_eq!(julian_to_gregorian(2459313.0), civil::date(2021, 4, 13));
assert_eq!(julian_to_gregorian(2415020.5), civil::date(1900, 1, 5));
}
}