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, Scale,
3 floor_f,
4};
5
6impl Dt {
7 pub const fn to_jd(&self) -> (i64, u128) {
14 let days_since_j2000 = self.to_attos().div_euclid(ATTOS_PER_DAY);
15 let remaining_attos = self.to_attos().rem_euclid(ATTOS_PER_DAY);
16
17 let jd_int = JD_2000_2_451_545.saturating_add(days_since_j2000 as i64);
18 (jd_int, remaining_attos as u128)
19 }
20
21 #[inline]
25 pub const fn to_jd_f(&self) -> Real {
26 let (days, attos) = self.to_jd();
27 f!(days) + f!(attos) / f!(ATTOS_PER_DAY)
28 }
29
30 pub const fn to_mjd(&self) -> (i64, u128) {
37 let (jd_days, frac_attos) = self.to_jd();
38
39 let mjd_days = jd_days.saturating_sub(2_400_001);
40 let mjd_attos = frac_attos.saturating_add(ATTOS_PER_HALF_DAY as u128);
41
42 if mjd_attos >= ATTOS_PER_DAY as u128 {
43 (
44 mjd_days.saturating_add(1),
45 mjd_attos.saturating_sub(ATTOS_PER_DAY as u128),
46 )
47 } else {
48 (mjd_days, mjd_attos)
49 }
50 }
51
52 #[inline]
56 pub const fn to_mjd_f(&self) -> Real {
57 let (days, attos) = self.to_mjd();
58 f!(days) + f!(attos) / f!(ATTOS_PER_DAY)
59 }
60
61 pub const fn from_jd(jd_days: i64, frac_attos: u128, on: Scale) -> Dt {
66 let days_since_j2000 = jd_days.saturating_sub(JD_2000_2_451_545);
67 let frac_attos_i128 = if frac_attos > i128::MAX as u128 {
68 i128::MAX
69 } else {
70 frac_attos as i128
71 };
72 let attos_from_days = (days_since_j2000 as i128).saturating_mul(ATTOS_PER_DAY);
73 let total_attos = attos_from_days.saturating_add(frac_attos_i128);
74
75 Self::from_attos(total_attos, on)
76 }
77
78 pub const fn from_mjd(mjd_days: i64, frac_attos: u128, on: Scale) -> Dt {
83 let jd_days = mjd_days.saturating_add(2_400_000);
84 let jd_attos = frac_attos.saturating_add(ATTOS_PER_HALF_DAY as u128);
85
86 if jd_attos >= ATTOS_PER_DAY as u128 {
87 Self::from_jd(
88 jd_days.saturating_add(1),
89 jd_attos.saturating_sub(ATTOS_PER_DAY as u128),
90 on,
91 )
92 } else {
93 Self::from_jd(jd_days, jd_attos, on)
94 }
95 }
96
97 pub const fn from_jd_f(jd: Real, on: Scale) -> Dt {
102 let jd_days_f = floor_f(jd);
103 let jd_days = jd_days_f as i64;
104
105 let mut frac_day = jd - jd_days_f;
106 if frac_day < 0.0 {
107 frac_day = 0.0;
108 } else if frac_day >= 1.0 {
109 frac_day = 1.0 - f64::EPSILON;
110 }
111
112 let total_sec_f = frac_day * 86_400.0;
113 let whole_sec = floor_f(total_sec_f) as i64;
114 let frac_sec = total_sec_f - (whole_sec as Real);
115
116 let attos_whole: i128 = (whole_sec as i128).saturating_mul(ATTOS_PER_SEC_I128);
117
118 let attos_frac_f = frac_sec * 1_000_000_000_000_000_000.0;
119 let attos_frac: i128 = floor_f(attos_frac_f + 0.5) as i128;
120
121 let mut total_attos: i128 = attos_whole.saturating_add(attos_frac);
122
123 let mut extra_days: i64 = 0;
124 if total_attos >= ATTOS_PER_DAY {
125 extra_days = 1;
126 total_attos = total_attos.saturating_sub(ATTOS_PER_DAY);
127 } else if total_attos < 0 {
128 extra_days = -1;
129 total_attos = total_attos.saturating_add(ATTOS_PER_DAY);
130 }
131
132 let final_jd_days = jd_days.saturating_add(extra_days);
133 let frac_attos = total_attos as u128;
134
135 Self::from_jd(final_jd_days, frac_attos, on)
136 }
137
138 #[inline]
143 pub const fn from_mjd_f(mjd: Real, on: Scale) -> Dt {
144 let jd = mjd + f!(2_400_000.5);
145 Self::from_jd_f(jd, on)
146 }
147}