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}