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)]
22pub struct RataDie(i64);
23
24impl RataDie {
25 pub const fn new(fixed_date: i64) -> Self {
27 let result = Self(fixed_date);
28 #[cfg(debug_assertions)]
29 result.check();
30 result
31 }
32
33 #[cfg(debug_assertions)]
35 pub const fn check(&self) {
36 if self.0 > i64::MAX / 256 {
37 debug_assert!(
38 false,
39 "RataDie is not designed to store values near to the overflow boundary"
40 );
41 }
42 if self.0 < i64::MIN / 256 {
43 debug_assert!(
44 false,
45 "RataDie is not designed to store values near to the overflow boundary"
46 );
47 }
48 }
49
50 #[doc(hidden)] pub const fn big_negative() -> Self {
53 Self::new(i64::MIN / 256 / 256)
54 }
55
56 pub const fn to_i64_date(self) -> i64 {
58 self.0
59 }
60
61 pub const fn to_f64_date(self) -> f64 {
63 self.0 as f64
64 }
65
66 pub const fn const_diff(self, rhs: Self) -> i64 {
68 self.0 - rhs.0
69 }
70
71 pub const fn as_moment(&self) -> Moment {
73 Moment::new(self.0 as f64)
74 }
75}
76
77impl fmt::Debug for RataDie {
78 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
79 let rd = self.0;
80 if let Ok((y, m, d)) = crate::iso::iso_from_fixed(*self) {
81 write!(f, "{rd} R.D. ({y}-{m:02}-{d:02})")
82 } else {
83 write!(f, "{rd} R.D. (out of bounds)")
84 }
85 }
86}
87
88impl Add<i64> for RataDie {
90 type Output = Self;
91 fn add(self, rhs: i64) -> Self::Output {
92 let result = Self(self.0 + rhs);
93 #[cfg(debug_assertions)]
94 result.check();
95 result
96 }
97}
98
99impl AddAssign<i64> for RataDie {
100 fn add_assign(&mut self, rhs: i64) {
101 self.0 += rhs;
102 #[cfg(debug_assertions)]
103 self.check();
104 }
105}
106
107impl Sub<i64> for RataDie {
109 type Output = Self;
110 fn sub(self, rhs: i64) -> Self::Output {
111 let result = Self(self.0 - rhs);
112 #[cfg(debug_assertions)]
113 result.check();
114 result
115 }
116}
117
118impl SubAssign<i64> for RataDie {
119 fn sub_assign(&mut self, rhs: i64) {
120 self.0 -= rhs;
121 #[cfg(debug_assertions)]
122 self.check();
123 }
124}
125
126impl Sub for RataDie {
128 type Output = i64;
129 fn sub(self, rhs: Self) -> Self::Output {
130 self.0 - rhs.0
131 }
132}
133
134#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
139pub struct Moment(f64);
140
141impl Add<f64> for Moment {
143 type Output = Self;
144 fn add(self, rhs: f64) -> Self::Output {
145 Self(self.0 + rhs)
146 }
147}
148
149impl AddAssign<f64> for Moment {
150 fn add_assign(&mut self, rhs: f64) {
151 self.0 += rhs;
152 }
153}
154
155impl Sub<f64> for Moment {
157 type Output = Self;
158 fn sub(self, rhs: f64) -> Self::Output {
159 Self(self.0 - rhs)
160 }
161}
162
163impl SubAssign<f64> for Moment {
164 fn sub_assign(&mut self, rhs: f64) {
165 self.0 -= rhs;
166 }
167}
168
169impl Sub for Moment {
171 type Output = f64;
172 fn sub(self, rhs: Self) -> Self::Output {
173 self.0 - rhs.0
174 }
175}
176
177impl Moment {
178 pub const fn new(value: f64) -> Moment {
180 Moment(value)
181 }
182
183 pub const fn inner(&self) -> f64 {
185 self.0
186 }
187
188 pub fn as_rata_die(&self) -> RataDie {
190 RataDie::new(self.0.floor() as i64)
191 }
192}
193
194#[test]
195fn test_moment_to_rata_die_conversion() {
196 for i in -1000..=1000 {
197 let moment = Moment::new(i as f64);
198 let rata_die = moment.as_rata_die();
199 assert_eq!(rata_die.to_i64_date(), i);
200 }
201}