use chrono::{DateTime, Datelike, TimeZone, Timelike, Utc};
#[derive(Debug, Clone)]
pub struct Time {
pub year: i32,
pub month: u32,
pub day: u32,
pub hour: u32,
pub minute: u32,
pub second: u32,
}
impl Time {
pub fn new(year: i32, month: u32, day: u32, hour: u32, minute: u32, second: u32) -> Time {
Time {
year,
month,
day,
hour,
minute,
second,
}
}
pub fn now() -> Time {
let utc = Utc::now();
Time {
year: utc.year(),
month: utc.month(),
day: utc.day(),
hour: utc.hour(),
minute: utc.minute(),
second: utc.second(),
}
}
pub fn from_utc(utc: DateTime<Utc>) -> Time {
Time {
year: utc.year(),
month: utc.month(),
day: utc.day(),
hour: utc.hour(),
minute: utc.minute(),
second: utc.second(),
}
}
pub fn from_isot_str(isot: &str) -> Time {
let utc = DateTime::parse_from_rfc3339(isot).unwrap();
Time {
year: utc.year(),
month: utc.month(),
day: utc.day(),
hour: utc.hour(),
minute: utc.minute(),
second: utc.second(),
}
}
pub fn from_jd(jd: f64) -> Time {
let temp = jd + 0.5;
let z = temp.floor() as i32;
let mut f = temp - z as f64;
let mut a = z;
if z > 2299161 {
let alpha = ((z as f64 - 1867216.25) / 36524.25).floor() as i32;
a = z + 1 + alpha - (alpha / 4);
}
let b = a + 1524;
let c = ((b as f64 - 122.1) / 365.25).floor();
let d = (365.25 * c) as i32;
let e = ((b as f64 - d as f64) / 30.6001).floor() as i32;
let day = b - d - ((30.6001 * e as f64) as i32) + f as i32;
let month = if e < 14 { e - 1 } else { e - 13 };
let year = if month > 2 { c - 4716.0 } else { c - 4715.0 };
let hour = ((f * 24.0) as i32).abs();
f = f - (hour as f64 / 24.0);
let minute = ((f * 1440.0) as i32).abs();
f = f - (minute as f64 / 1440.0);
let second = ((f * 86400.0) as i32).abs();
Time {
year: year as i32,
month: month as u32,
day: day as u32,
hour: hour as u32,
minute: minute as u32,
second: second as u32,
}
}
pub fn from_mjd(mjd: f64) -> Time {
Time::from_jd(mjd + 2400000.5)
}
pub fn to_jd(&self) -> f64 {
let year = self.year as f64;
let month = self.month as f64;
let day = self.day as f64;
let hour = self.hour as f64;
let minute = self.minute as f64;
let second = self.second as f64;
let jd = 367.0 * year - ((year + ((month + 9.0) / 12.0)).floor() * 7.0 / 4.0).floor()
+ ((275.0 * month) / 9.0).floor()
+ day
+ 1721013.5
+ ((hour + (minute / 60.0) + (second / 3600.0)) / 24.0);
jd
}
pub fn to_mjd(&self) -> f64 {
self.to_jd() - 2400000.5
}
pub fn to_gst(&self) -> f64 {
let jd = self.to_jd();
let t = (jd - 2451545.0) / 36525.0;
let gst = 280.46061837 + 360.98564736629 * (jd - 2451545.0) + 0.000387933 * t * t
- (t * t * t) / 38710000.0;
gst % 360.0
}
pub fn to_utc(&self) -> DateTime<Utc> {
Utc.with_ymd_and_hms(
self.year,
self.month,
self.day,
self.hour,
self.minute,
self.second,
)
.unwrap()
}
pub fn to_string(&self, format: Option<&str>) -> String {
if let Some(format) = format {
if format == "jd" {
return self.to_jd().to_string();
} else if format == "mjd" {
return self.to_mjd().to_string();
} else if format == "utc" {
return self.to_utc().to_string();
} else if format == "isot" {
return self.to_utc().to_rfc3339();
} else {
return "Invalid format".to_string();
}
} else {
return self.to_utc().to_string();
}
}
}
impl std::fmt::Display for Time {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"{}-{:02}-{:02} {:02}:{:02}:{:02}",
self.year, self.month, self.day, self.hour, self.minute, self.second
)
}
}