use angle;
pub enum CalType {
Gregorian,
Julian
}
pub struct Date {
pub year: i16,
pub month: u8,
pub decimal_day: f64,
pub cal_type: CalType,
}
pub struct DayOfMonth {
pub day: u8,
pub hr: u8,
pub min: u8,
pub sec: f64,
pub time_zone: f64,
}
pub fn decimal_day(day: &DayOfMonth) -> f64 {
(day.day as f64)
+ (day.hr as f64) / 24.0
+ (day.min as f64) / 60.0
+ day.sec / 60.0
- day.time_zone / 24.0
}
pub fn decimal_year(date: &Date) -> f64 {
let mut y = 0;
let mut days = 365.0;
if date.month > 1 { y += 31; }
if date.month > 2 {
y += 28;
if is_leap_year(date.year, &date.cal_type) {
y += 1;
days += 1.0;
}
}
if date.month > 3 { y += 31; }
if date.month > 4 { y += 30; }
if date.month > 5 { y += 31; }
if date.month > 6 { y += 30; }
if date.month > 7 { y += 31; }
if date.month > 8 { y += 31; }
if date.month > 9 { y += 30; }
if date.month > 10 { y += 31; }
if date.month > 11 { y += 30; }
(date.year as f64) + ((y as f64) + date.decimal_day)/days
}
pub fn is_leap_year(year: i16, cal_type: &CalType) -> (bool) {
match cal_type {
&CalType::Julian => year % 4 == 0,
&CalType::Gregorian => {
if year % 100 == 0 { year % 400 == 0 }
else { year % 4 == 0 }
},
}
}
#[inline]
pub fn julian_cent(JD: f64) -> f64 {
(JD - 2451545.0) / 36525.0
}
#[inline]
pub fn julian_mill(JD: f64) -> f64 {
(JD - 2451545.0) / 365250.0
}
pub fn julian_day(date: &Date) -> f64 {
let (y, m) =
if date.month == 1 || date.month == 2 {
((date.year - 1) as f64, (date.month + 12) as f64)
} else {
(date.year as f64, date.month as f64)
};
let a = (y / 100.0).floor();
let b = match date.cal_type {
CalType::Gregorian => 2.0 - a + (a / 4.0).floor(),
CalType::Julian => 0.0,
};
(365.25 * (y + 4716.0)).floor()
+ (30.6001 * (m + 1.0)).floor()
+ date.decimal_day
+ b
- 1524.5
}
#[inline]
pub fn julian_ephemeris_day(JD: f64, delta_t: f64) -> f64 {
delta_t/86400.0 + JD
}
pub fn date_frm_julian_day<'a> (mut JD: f64) -> Result<(i16, u8, f64), &'a str> {
if JD < 0.0 {
return Err("A negative value for JD was passed to time::date_frm_julian_day()");
}
JD += 0.5;
let Z = JD as i64;
let F = JD - (Z as f64);
let A = if Z < 2299161 {
Z
} else {
let alpha = (((Z as f64) - 1867216.25) / 36524.25).floor() as i64;
Z + 1 + alpha - ( ( (alpha as f64)/4.0 ).floor() as i64 )
};
let B = A + 1524;
let C = ( ( (B as f64) - 122.1 )/365.25 ).floor() as i64;
let D = (365.25 * (C as f64)).floor() as i64;
let E = ( ( (B - D) as f64 )/30.6001 ).floor() as i64;
let day = ((B - D) as f64) - (30.6001 * (E as f64)).floor() + F;
let month = if E < 14 { E - 1 }
else if E == 14 || E == 15 { E - 13 }
else {
return Err("Internal error in time::date_frm_julian_day()");
};
let year = if month > 2 { C - 4716 }
else if month == 1 || month == 2 { C - 4715 }
else {
return Err("Internal error in time::date_frm_julian_day()");
};
Ok( (year as i16, month as u8, day) )
}
pub fn apprnt_sidr(mn_sidr: f64, nut_in_long: f64, true_oblq: f64) -> f64 {
mn_sidr + nut_in_long*true_oblq.cos()
}
#[macro_export]
macro_rules! apprnt_sidr {
($JD: expr) => {{
let (nut_in_long, nut_in_oblq) = astro::nutation::nutation($JD);
let eclip_oblq = astro::ecliptic::mn_oblq_laskar($JD);
astro::time::apprnt_sidr (
astro::time::mn_sidr($JD), nut_in_long, eclip_oblq + nut_in_oblq
)
}};
}
pub fn mn_sidr(JD: f64) -> f64 {
let JC = julian_cent(JD);
angle::limit_to_360 (
280.46061837
+ 360.98564736629 * (JD - 2451545.0)
+ JC * JC * (0.000387933 - JC/38710000.0)
).to_radians()
}
pub fn delta_t(year: i32, month: u8) -> f64 {
let y = (year as f64) + ((month as f64) - 0.5)/12.0;
if y < -500.0 {
let u = (y - 1820.0) / 100.0;
return 32.0*u*u - 20.0;
}
else if y < 500.0 {
let u = y / 100.0;
return 10583.6 -
u * (1014.41 +
u * (33.78311 +
u * (5.952053 -
u * (0.1798452 -
u * (0.022174192 -
u * 0.0090316521)
))));
}
else if y < 1600.0 {
let u = (y - 1000.0) / 100.0;
return 1574.2 -
u * (556.01 -
u * (71.23472 +
u * (0.319781 -
u * (0.8503463 +
u * (0.005050998 -
u * 0.0083572073)
))));
}
else if y < 1700.0 {
let u = y - 1600.0;
return 120.0 -
u * (0.9808 +
u * (0.01532 -
u / 7129.0
));
}
else if y < 1800.0 {
let u = y - 1700.0;
return 8.83 +
u * (0.1603 -
u * (0.0059285 -
u * (0.00013336 +
u / 1174000.0
)));
}
else if y < 1860.0 {
let u = y - 1800.0;
return 13.72 -
u * (0.332447 -
u * (0.0068612 +
u * (0.0041116 -
u * (0.00037436 -
u * (0.0000121272 +
u * (0.0000001699 -
u * 0.000000000875
))))));
}
else if y < 1900.0 {
let u = y - 1860.0;
return 7.62 +
u * (0.5737 -
u * (0.251754 -
u * (0.01680668 -
u * (0.0004473624 +
u / 233174.0
))));
}
else if y < 1920.0 {
let u = y - 1900.0;
return -2.79 +
u * (1.494119 -
u * (0.0598939 -
u * (0.0061966 +
u * 0.000197
)));
}
else if y < 1941.0 {
let u = y - 1920.0;
return 21.20 +
u * (0.84493 -
u * (0.076100 -
u * 0.0020936
));
}
else if y < 1961.0 {
let u = y - 1950.0;
return 29.07 +
u * (0.407 -
u * ((1.0 / 233.0) -
u / 2547.0
));
}
else if y < 1986.0 {
let u = y - 1975.0;
return 45.45 +
u * (1.067 -
u * ((1.0 / 260.0) +
u / 718.0)
);
}
else if y < 2005.0 {
let u = y - 2000.0;
return 63.86 +
u * (0.3345 -
u * (0.060374 -
u * (0.0017275 +
u * (0.000651814 +
u * 0.00002373599)
)));
}
else if y < 2050.0 {
let u = y - 2000.0;
return 62.92 +
u * (0.32217 +
u * 0.005589);
}
else if y <= 2150.0 {
let u = (y - 1820.0) / 100.0;
return 32.0*u*u - 20.0 - 0.5628*(2150.0 - y);
}
else if y > 2150.0 {
let u = (y - 1820.0) / 100.0;
return 32.0*u*u - 20.0;
}
0.0
}