Skip to main content

astronomy/
time.rs

1use rust_decimal::Decimal;
2use rust_decimal::prelude::{FromPrimitive, ToPrimitive};
3use std::fmt::{self, Display};
4use std::ops::Add;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
7pub struct Time(Decimal);
8
9impl Time {
10    pub fn from_gps_seconds(seconds: f64) -> Self {
11        Time(Decimal::from_f64(seconds).expect("Failed to convert f64 to Decimal for Time."))
12    }
13
14    pub fn as_gps_seconds_f64(&self) -> f64 {
15        self.0
16            .to_f64()
17            .expect("Failed to convert Decimal to f64 for Time.")
18    }
19}
20
21// Implementing the Display trait for Time
22// This is useful for printing Time instances.
23impl Display for Time {
24    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25        write!(f, "{}", self.0)
26    }
27}
28impl Add for Time {
29    type Output = Self;
30
31    fn add(self, other: Self) -> Self::Output {
32        Time(self.0 + other.0)
33    }
34}
35
36#[cfg(test)]
37mod tests {
38    use super::*;
39
40    #[test]
41    fn test_time_from_gps_seconds() {
42        let time = Time::from_gps_seconds(123456.789);
43        assert_eq!(time.as_gps_seconds_f64(), 123456.789);
44    }
45
46    #[test]
47    fn test_time_display() {
48        let time = Time::from_gps_seconds(98765.4321);
49        assert_eq!(format!("{}", time), "98765.4321");
50    }
51
52    #[test]
53    fn test_time_equality() {
54        let time1 = Time::from_gps_seconds(100.0);
55        let time2 = Time::from_gps_seconds(100.0);
56        let time3 = Time::from_gps_seconds(200.0);
57
58        assert_eq!(time1, time2);
59        assert_ne!(time1, time3);
60        assert!(time1 < time3);
61    }
62
63    #[test]
64    fn test_time_addition() {
65        let time1 = Time::from_gps_seconds(50.0);
66        let time2 = Time::from_gps_seconds(25.0);
67        let result = time1 + time2;
68
69        assert_eq!(result.as_gps_seconds_f64(), 75.0);
70    }
71
72    #[test]
73    fn test_time_ordering() {
74        let time1 = Time::from_gps_seconds(300.0);
75        let time2 = Time::from_gps_seconds(400.0);
76        let time3 = Time::from_gps_seconds(300.0);
77
78        assert!(time1 < time2);
79        assert!(time1 <= time3);
80        assert!(time2 > time1);
81        assert!(time2 >= time3);
82    }
83
84    #[test]
85    fn test_time_conversion() {
86        let time = Time::from_gps_seconds(123456.789);
87        let gps_seconds = time.as_gps_seconds_f64();
88        assert_eq!(gps_seconds, 123456.789);
89    }
90
91    #[test]
92    fn test_time_from_decimal() {
93        let decimal_time = Decimal::from_f64(123456.789).expect("Failed to create Decimal");
94        let time = Time(decimal_time);
95        assert_eq!(time.as_gps_seconds_f64(), 123456.789);
96    }
97
98    #[test]
99    #[allow(clippy::excessive_precision)]
100    fn test_time_creation_and_conversion() {
101        let gps_time = 1126259446.0;
102        let time_obj = Time::from_gps_seconds(gps_time);
103        assert_eq!(time_obj.as_gps_seconds_f64(), gps_time);
104
105        let precise_gps_time = 123456789.123456789;
106        let time_obj_precise = Time::from_gps_seconds(precise_gps_time);
107        // Due to f64 precision, we might not get the exact value back
108        // For Decimal, it shoiuld be exact
109
110        assert_eq!(
111            time_obj_precise.0,
112            Decimal::from_f64(precise_gps_time).unwrap()
113        );
114    }
115}