deep_time/dt/
julian_date.rs1use crate::{
2 ATTOS_PER_DAY, ATTOS_PER_HALF_DAY, ATTOS_PER_SEC_I128, Dt, JD_2000_2_451_545, Real,
3 SEC_PER_DAYI64, Scale, floor_f,
4};
5
6impl Dt {
7 pub const fn to_jd(&self) -> (i64, u128) {
14 let days_since_j2000 = self.sec.div_euclid(SEC_PER_DAYI64);
15 let remaining_sec = self.sec.rem_euclid(SEC_PER_DAYI64);
16
17 let frac_attos =
18 (remaining_sec as u128) * ATTOS_PER_SEC_I128 as u128 + (self.attos as u128);
19
20 let jd_int = JD_2000_2_451_545.saturating_add(days_since_j2000);
21 (jd_int, frac_attos)
22 }
23
24 #[inline]
28 pub const fn to_jd_f(&self) -> Real {
29 let (days, attos) = self.to_jd();
30 f!(days) + f!(attos) / f!(ATTOS_PER_DAY)
31 }
32
33 pub const fn to_mjd(&self) -> (i64, u128) {
40 let (jd_days, frac_attos) = self.to_jd();
41
42 let mjd_days = jd_days.saturating_sub(2_400_001);
43 let mjd_attos = frac_attos.saturating_add(ATTOS_PER_HALF_DAY as u128);
44
45 if mjd_attos >= ATTOS_PER_DAY as u128 {
46 (
47 mjd_days.saturating_add(1),
48 mjd_attos.saturating_sub(ATTOS_PER_DAY as u128),
49 )
50 } else {
51 (mjd_days, mjd_attos)
52 }
53 }
54
55 #[inline]
59 pub const fn to_mjd_f(&self) -> Real {
60 let (days, attos) = self.to_mjd();
61 f!(days) + f!(attos) / f!(ATTOS_PER_DAY)
62 }
63
64 pub const fn from_jd(jd_days: i64, frac_attos: u128, on: Scale) -> Self {
69 let days_since_j2000 = jd_days.saturating_sub(JD_2000_2_451_545);
70 let seconds_from_days = days_since_j2000.saturating_mul(SEC_PER_DAYI64);
71
72 let extra_seconds = {
73 let quot = frac_attos / (ATTOS_PER_SEC_I128 as u128);
74 if quot > i64::MAX as u128 {
75 i64::MAX
76 } else {
77 quot as i64
78 }
79 };
80
81 let total_sec = seconds_from_days.saturating_add(extra_seconds);
82 let attos = (frac_attos % (ATTOS_PER_SEC_I128 as u128)) as u64;
83
84 Dt::from(total_sec, attos, on)
85 }
86
87 pub const fn from_mjd(mjd_days: i64, frac_attos: u128, on: Scale) -> Self {
92 let jd_days = mjd_days.saturating_add(2_400_000);
93 let jd_attos = frac_attos.saturating_add(ATTOS_PER_HALF_DAY as u128);
94
95 if jd_attos >= ATTOS_PER_DAY as u128 {
96 Self::from_jd(
97 jd_days.saturating_add(1),
98 jd_attos.saturating_sub(ATTOS_PER_DAY as u128),
99 on,
100 )
101 } else {
102 Self::from_jd(jd_days, jd_attos, on)
103 }
104 }
105
106 pub const fn from_jd_f(jd: Real, on: Scale) -> Self {
111 let jd_days_f = floor_f(jd);
112 let jd_days = jd_days_f as i64;
113
114 let mut frac_day = jd - jd_days_f;
115 if frac_day < 0.0 {
116 frac_day = 0.0;
117 } else if frac_day >= 1.0 {
118 frac_day = 1.0 - f64::EPSILON;
119 }
120
121 let total_sec_f = frac_day * 86_400.0;
122 let whole_sec = floor_f(total_sec_f) as i64;
123 let frac_sec = total_sec_f - (whole_sec as Real);
124
125 let attos_whole: i128 = (whole_sec as i128).saturating_mul(ATTOS_PER_SEC_I128);
126
127 let attos_frac_f = frac_sec * 1_000_000_000_000_000_000.0;
128 let attos_frac: i128 = floor_f(attos_frac_f + 0.5) as i128;
129
130 let mut total_attos: i128 = attos_whole + attos_frac;
131
132 let mut extra_days: i64 = 0;
133 if total_attos >= ATTOS_PER_DAY {
134 extra_days = 1;
135 total_attos -= ATTOS_PER_DAY;
136 } else if total_attos < 0 {
137 extra_days = -1;
138 total_attos += ATTOS_PER_DAY;
139 }
140
141 let final_jd_days = jd_days.saturating_add(extra_days);
142 let frac_attos = total_attos as u128;
143
144 Self::from_jd(final_jd_days, frac_attos, on)
145 }
146
147 #[inline]
152 pub const fn from_mjd_f(mjd: Real, on: Scale) -> Self {
153 let jd = mjd + f!(2_400_000.5);
154 Self::from_jd_f(jd, on)
155 }
156}