calendrical_calculations/
rata_die.rs1use core::fmt;
11use core::ops::{Add, AddAssign, Sub, SubAssign};
12#[allow(unused_imports)]
13use core_maths::*;
14
15#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
24pub struct RataDie(i64);
25
26impl RataDie {
27    pub const fn new(fixed_date: i64) -> Self {
33        let result = Self(fixed_date);
34        #[cfg(debug_assertions)]
35        result.check();
36        result
37    }
38
39    #[cfg(debug_assertions)]
41    const fn check(self) {
42        if self.0 > i64::MAX / 256 {
43            debug_assert!(
44                false,
45                "RataDie is not designed to store values near to the overflow boundary"
46            );
47        }
48        if self.0 < i64::MIN / 256 {
49            debug_assert!(
50                false,
51                "RataDie is not designed to store values near to the overflow boundary"
52            );
53        }
54    }
55
56    #[doc(hidden)] pub const fn big_negative() -> Self {
59        Self::new(i64::MIN / 256 / 256)
60    }
61
62    pub const fn to_i64_date(self) -> i64 {
64        self.0
65    }
66
67    pub(crate) const fn to_f64_date(self) -> f64 {
69        self.0 as f64
70    }
71
72    pub const fn since(self, rhs: Self) -> i64 {
80        self.0 - rhs.0
81    }
82
83    pub const fn until(self, rhs: Self) -> i64 {
91        rhs.0 - self.0
92    }
93
94    pub const fn add(self, rhs: i64) -> Self {
96        let result = Self(self.0 + rhs);
97        #[cfg(debug_assertions)]
98        result.check();
99        result
100    }
101
102    pub(crate) const fn as_moment(self) -> Moment {
104        Moment::new(self.0 as f64)
105    }
106}
107
108impl fmt::Debug for RataDie {
109    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
110        let rd = self.0;
111        if let Ok((y, m, d)) = crate::iso::iso_from_fixed(*self) {
112            write!(f, "{rd} R.D. ({y}-{m:02}-{d:02})")
113        } else {
114            write!(f, "{rd} R.D. (out of bounds)")
115        }
116    }
117}
118
119impl Add<i64> for RataDie {
121    type Output = Self;
122    fn add(self, rhs: i64) -> Self::Output {
123        self.add(rhs)
124    }
125}
126
127impl AddAssign<i64> for RataDie {
128    fn add_assign(&mut self, rhs: i64) {
129        self.0 += rhs;
130    }
131}
132
133impl Sub<i64> for RataDie {
135    type Output = Self;
136    fn sub(self, rhs: i64) -> Self::Output {
137        let result = Self(self.0 - rhs);
138        #[cfg(debug_assertions)]
139        result.check();
140        result
141    }
142}
143
144impl SubAssign<i64> for RataDie {
145    fn sub_assign(&mut self, rhs: i64) {
146        self.0 -= rhs;
147    }
148}
149
150impl Sub for RataDie {
152    type Output = i64;
153    fn sub(self, rhs: Self) -> Self::Output {
154        self.since(rhs)
155    }
156}
157
158#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
163pub(crate) struct Moment(f64);
164
165impl Add<f64> for Moment {
167    type Output = Self;
168    fn add(self, rhs: f64) -> Self::Output {
169        Self(self.0 + rhs)
170    }
171}
172
173impl AddAssign<f64> for Moment {
174    fn add_assign(&mut self, rhs: f64) {
175        self.0 += rhs;
176    }
177}
178
179impl Sub<f64> for Moment {
181    type Output = Self;
182    fn sub(self, rhs: f64) -> Self::Output {
183        Self(self.0 - rhs)
184    }
185}
186
187impl SubAssign<f64> for Moment {
188    fn sub_assign(&mut self, rhs: f64) {
189        self.0 -= rhs;
190    }
191}
192
193impl Sub for Moment {
195    type Output = f64;
196    fn sub(self, rhs: Self) -> Self::Output {
197        self.0 - rhs.0
198    }
199}
200
201impl Moment {
202    pub const fn new(value: f64) -> Moment {
204        Moment(value)
205    }
206
207    pub const fn inner(self) -> f64 {
209        self.0
210    }
211
212    pub fn as_rata_die(self) -> RataDie {
214        RataDie::new(self.0.floor() as i64)
215    }
216}
217
218#[test]
219fn test_moment_to_rata_die_conversion() {
220    for i in -1000..=1000 {
221        let moment = Moment::new(i as f64);
222        let rata_die = moment.as_rata_die();
223        assert_eq!(rata_die.to_i64_date(), i);
224    }
225}