erfa_rust/
G9_safe.rs

1// G9
2//   d2tf.c   → eraD2tf_safe
3//   d2dtf.c  → eraD2dtf_safe
4//   dat.c    → eraDat_safe
5
6use crate::G14_safe::eraDatini_safe;
7use crate::G19_safe::eraJd2cal_safe;
8use crate::G8_safe::eraCal2jd_safe;
9use crate::H1_safe::{eraLEAPSECOND, ERFA_DAYSEC, ERFA_DINT, ERFA_DNINT};
10
11pub type ErfaResult<T> = Result<T, ()>;
12
13// G9/d2tf.c → eraD2tf_safe
14// Convert interval in days to sign and HMS with fractional field.
15pub fn eraD2tf_safe(ndp: i32, days: f64) -> ErfaResult<(char, [i32; 4])> {
16    let sign = if days >= 0.0 { '+' } else { '-' };
17
18    let mut a = ERFA_DAYSEC * days.abs();
19
20    if ndp < 0 {
21        let mut nrs = 1;
22        for n in 1..=-ndp {
23            nrs *= if n == 2 || n == 4 { 6 } else { 10 };
24        }
25        let rs = nrs as f64;
26        let w = a / rs;
27        a = rs * ERFA_DNINT(w);
28    }
29
30    let mut nrs = 1;
31    for _ in 1..=ndp.max(0) {
32        nrs *= 10;
33    }
34    let rs = nrs as f64;
35    let rm = rs * 60.0;
36    let rh = rm * 60.0;
37
38    a = ERFA_DNINT(rs * a);
39
40    let ah = ERFA_DINT(a / rh);
41    a -= ah * rh;
42    let am = ERFA_DINT(a / rm);
43    a -= am * rm;
44    let as_ = ERFA_DINT(a / rs);
45    let af = a - as_ * rs;
46
47    let ihmsf = [ah as i32, am as i32, as_ as i32, af as i32];
48    Ok((sign, ihmsf))
49}
50
51// G9/d2dtf.c → eraD2dtf_safe
52// Format two-part JD into calendar date and time fields for a given scale.
53pub fn eraD2dtf_safe(
54    scale: &str,
55    ndp: i32,
56    d1: f64,
57    d2: f64,
58) -> ErfaResult<((i32, i32, i32), [i32; 4], i32)> {
59    let ((iy0, im0, id0), mut fd, j_cal) = eraJd2cal_safe(d1, d2)?;
60    if j_cal != 0 {
61        return Err(());
62    }
63    let (mut iy1, mut im1, mut id1) = (iy0, im0, id0);
64
65    let mut js = 0;
66    let mut leap = false;
67
68    if scale == "UTC" {
69        let (dat0, j0) = eraDat_safe(iy1, im1, id1, 0.0)?;
70        if j0 < 0 {
71            return Err(());
72        }
73        if j0 > 0 {
74            js = j0;
75        }
76
77        let (dat12, j12) = eraDat_safe(iy1, im1, id1, 0.5)?;
78        if j12 < 0 {
79            return Err(());
80        }
81        if j12 > 0 && js == 0 {
82            js = j12;
83        }
84
85        let ((iy2, im2, id2), _w, j_next) = eraJd2cal_safe(d1 + 1.5, d2 - fd)?;
86        if j_next != 0 {
87            return Err(());
88        }
89        let (dat24, j24) = eraDat_safe(iy2, im2, id2, 0.0)?;
90        if j24 < 0 {
91            return Err(());
92        }
93        if j24 > 0 && js == 0 {
94            js = j24;
95        }
96
97        let dleap = dat24 - (2.0 * dat12 - dat0);
98        leap = dleap.abs() > 0.5;
99        if leap {
100            fd += fd * dleap / ERFA_DAYSEC;
101        }
102    }
103
104    let (_s, mut ihmsf1) = eraD2tf_safe(ndp, fd)?;
105
106    if ihmsf1[0] > 23 {
107        let ((iy2, im2, id2), _w, j_next) = eraJd2cal_safe(d1 + 1.5, d2 - fd)?;
108        if j_next != 0 {
109            return Err(());
110        }
111
112        if !leap {
113            iy1 = iy2;
114            im1 = im2;
115            id1 = id2;
116            ihmsf1 = [0, 0, 0, 0];
117        } else {
118            if ihmsf1[2] > 0 {
119                iy1 = iy2;
120                im1 = im2;
121                id1 = id2;
122                ihmsf1 = [0, 0, 0, 0];
123            } else {
124                ihmsf1[0] = 23;
125                ihmsf1[1] = 59;
126                ihmsf1[2] = 60;
127            }
128            if ndp < 0 && ihmsf1[2] == 60 {
129                iy1 = iy2;
130                im1 = im2;
131                id1 = id2;
132                ihmsf1 = [0, 0, 0, 0];
133            }
134        }
135    }
136
137    Ok(((iy1, im1, id1), ihmsf1, js))
138}
139
140// G9/dat.c → eraDat_safe
141// TAI−UTC = ΔAT for a given date; returns (ΔAT seconds, status).
142pub fn eraDat_safe(iy: i32, im: i32, id: i32, fd: f64) -> ErfaResult<(f64, i32)> {
143    const IYV: i32 = 2023;
144
145    const DRIFT: &[[f64; 2]] = &[
146        [37300.0, 0.0012960],
147        [37300.0, 0.0012960],
148        [37300.0, 0.0012960],
149        [37665.0, 0.0011232],
150        [37665.0, 0.0011232],
151        [38761.0, 0.0012960],
152        [38761.0, 0.0012960],
153        [38761.0, 0.0012960],
154        [38761.0, 0.0012960],
155        [38761.0, 0.0012960],
156        [38761.0, 0.0012960],
157        [38761.0, 0.0012960],
158        [39126.0, 0.0025920],
159        [39126.0, 0.0025920],
160    ];
161    const NERA1: usize = DRIFT.len();
162
163    const CHANGES_BUILTIN: &[eraLEAPSECOND] = &[
164        eraLEAPSECOND {
165            iyear: 1960,
166            month: 1,
167            delat: 1.4178180,
168        },
169        eraLEAPSECOND {
170            iyear: 1961,
171            month: 1,
172            delat: 1.4228180,
173        },
174        eraLEAPSECOND {
175            iyear: 1961,
176            month: 8,
177            delat: 1.3728180,
178        },
179        eraLEAPSECOND {
180            iyear: 1962,
181            month: 1,
182            delat: 1.8458580,
183        },
184        eraLEAPSECOND {
185            iyear: 1963,
186            month: 11,
187            delat: 1.9458580,
188        },
189        eraLEAPSECOND {
190            iyear: 1964,
191            month: 1,
192            delat: 3.2401300,
193        },
194        eraLEAPSECOND {
195            iyear: 1964,
196            month: 4,
197            delat: 3.3401300,
198        },
199        eraLEAPSECOND {
200            iyear: 1964,
201            month: 9,
202            delat: 3.4401300,
203        },
204        eraLEAPSECOND {
205            iyear: 1965,
206            month: 1,
207            delat: 3.5401300,
208        },
209        eraLEAPSECOND {
210            iyear: 1965,
211            month: 3,
212            delat: 3.6401300,
213        },
214        eraLEAPSECOND {
215            iyear: 1965,
216            month: 7,
217            delat: 3.7401300,
218        },
219        eraLEAPSECOND {
220            iyear: 1965,
221            month: 9,
222            delat: 3.8401300,
223        },
224        eraLEAPSECOND {
225            iyear: 1966,
226            month: 1,
227            delat: 4.3131700,
228        },
229        eraLEAPSECOND {
230            iyear: 1968,
231            month: 2,
232            delat: 4.2131700,
233        },
234        eraLEAPSECOND {
235            iyear: 1972,
236            month: 1,
237            delat: 10.0,
238        },
239        eraLEAPSECOND {
240            iyear: 1972,
241            month: 7,
242            delat: 11.0,
243        },
244        eraLEAPSECOND {
245            iyear: 1973,
246            month: 1,
247            delat: 12.0,
248        },
249        eraLEAPSECOND {
250            iyear: 1974,
251            month: 1,
252            delat: 13.0,
253        },
254        eraLEAPSECOND {
255            iyear: 1975,
256            month: 1,
257            delat: 14.0,
258        },
259        eraLEAPSECOND {
260            iyear: 1976,
261            month: 1,
262            delat: 15.0,
263        },
264        eraLEAPSECOND {
265            iyear: 1977,
266            month: 1,
267            delat: 16.0,
268        },
269        eraLEAPSECOND {
270            iyear: 1978,
271            month: 1,
272            delat: 17.0,
273        },
274        eraLEAPSECOND {
275            iyear: 1979,
276            month: 1,
277            delat: 18.0,
278        },
279        eraLEAPSECOND {
280            iyear: 1980,
281            month: 1,
282            delat: 19.0,
283        },
284        eraLEAPSECOND {
285            iyear: 1981,
286            month: 7,
287            delat: 20.0,
288        },
289        eraLEAPSECOND {
290            iyear: 1982,
291            month: 7,
292            delat: 21.0,
293        },
294        eraLEAPSECOND {
295            iyear: 1983,
296            month: 7,
297            delat: 22.0,
298        },
299        eraLEAPSECOND {
300            iyear: 1985,
301            month: 7,
302            delat: 23.0,
303        },
304        eraLEAPSECOND {
305            iyear: 1988,
306            month: 1,
307            delat: 24.0,
308        },
309        eraLEAPSECOND {
310            iyear: 1990,
311            month: 1,
312            delat: 25.0,
313        },
314        eraLEAPSECOND {
315            iyear: 1991,
316            month: 1,
317            delat: 26.0,
318        },
319        eraLEAPSECOND {
320            iyear: 1992,
321            month: 7,
322            delat: 27.0,
323        },
324        eraLEAPSECOND {
325            iyear: 1993,
326            month: 7,
327            delat: 28.0,
328        },
329        eraLEAPSECOND {
330            iyear: 1994,
331            month: 7,
332            delat: 29.0,
333        },
334        eraLEAPSECOND {
335            iyear: 1996,
336            month: 1,
337            delat: 30.0,
338        },
339        eraLEAPSECOND {
340            iyear: 1997,
341            month: 7,
342            delat: 31.0,
343        },
344        eraLEAPSECOND {
345            iyear: 1999,
346            month: 1,
347            delat: 32.0,
348        },
349        eraLEAPSECOND {
350            iyear: 2006,
351            month: 1,
352            delat: 33.0,
353        },
354        eraLEAPSECOND {
355            iyear: 2009,
356            month: 1,
357            delat: 34.0,
358        },
359        eraLEAPSECOND {
360            iyear: 2012,
361            month: 7,
362            delat: 35.0,
363        },
364        eraLEAPSECOND {
365            iyear: 2015,
366            month: 7,
367            delat: 36.0,
368        },
369        eraLEAPSECOND {
370            iyear: 2017,
371            month: 1,
372            delat: 37.0,
373        },
374    ];
375
376    if fd < 0.0 || fd > 1.0 {
377        return Err(());
378    }
379
380    let ((_, djm), jcal) = eraCal2jd_safe(iy, im, id)?;
381    if jcal < 0 {
382        return Err(());
383    }
384
385    let table = eraDatini_safe(CHANGES_BUILTIN)?;
386
387    if iy < table[0].iyear {
388        return Ok((0.0, 1));
389    }
390
391    let mut j = 0;
392    if iy > IYV + 5 {
393        j = 1;
394    }
395
396    let m = 12 * iy + im;
397
398    let mut idx = None;
399    for i in (0..table.len()).rev() {
400        if m >= (12 * table[i].iyear + table[i].month) {
401            idx = Some(i);
402            break;
403        }
404    }
405    let i = match idx {
406        Some(i) => i,
407        None => return Err(()),
408    };
409
410    let mut da = table[i].delat;
411
412    if i < NERA1 {
413        da += (djm + fd - DRIFT[i][0]) * DRIFT[i][1];
414    }
415
416    Ok((da, j))
417}