Skip to main content

tempoch_core/format/
impls.rs

1// SPDX-License-Identifier: AGPL-3.0-only
2// Copyright (C) 2026 Vallés Puig, Ramon
3
4//! `FormatForScale` / `InfallibleFormatForScale` for built-in format markers.
5
6use super::markers::{J2000s, Unix, GPS, JD, MJD};
7use super::traits::{FormatForScale, InfallibleFormatForScale};
8use crate::earth::context::TimeContext;
9use crate::encoding::{day_to_j2000_seconds, j2000_seconds_to_day};
10use crate::format::TimeFormat;
11use crate::foundation::error::ConversionError;
12use crate::model::scale::{CoordinateScale, TAI, UTC};
13use crate::model::time::Time;
14use qtty::{Day, Second};
15
16impl<S: CoordinateScale> FormatForScale<S> for J2000s {
17    #[inline]
18    fn try_from_time<Fin: TimeFormat>(
19        time: Time<S, Fin>,
20        _ctx: &TimeContext,
21    ) -> Result<Second, ConversionError> {
22        Ok(<Self as InfallibleFormatForScale<S>>::from_time(time))
23    }
24
25    #[inline]
26    fn try_into_time(raw: Second, _ctx: &TimeContext) -> Result<Time<S, Self>, ConversionError> {
27        Ok(<Self as InfallibleFormatForScale<S>>::into_time(raw))
28    }
29}
30
31impl<S: CoordinateScale> InfallibleFormatForScale<S> for J2000s {
32    #[inline]
33    fn from_time<Fin: TimeFormat>(time: Time<S, Fin>) -> Second {
34        time.to_j2000s().raw_j2000_seconds()
35    }
36
37    #[inline]
38    fn into_time(raw: Second) -> Time<S, Self> {
39        Time::<S, J2000s>::from_raw_j2000_seconds(raw).expect("finite J2000 seconds must decode")
40    }
41}
42
43impl<S: CoordinateScale> FormatForScale<S> for JD {
44    #[inline]
45    fn try_from_time<Fin: TimeFormat>(
46        time: Time<S, Fin>,
47        _ctx: &TimeContext,
48    ) -> Result<Day, ConversionError> {
49        Ok(<Self as InfallibleFormatForScale<S>>::from_time(time))
50    }
51
52    #[inline]
53    fn try_into_time(raw: Day, _ctx: &TimeContext) -> Result<Time<S, Self>, ConversionError> {
54        Ok(<Self as InfallibleFormatForScale<S>>::into_time(raw))
55    }
56}
57
58impl<S: CoordinateScale> InfallibleFormatForScale<S> for JD {
59    #[inline]
60    fn from_time<Fin: TimeFormat>(time: Time<S, Fin>) -> Day {
61        j2000_seconds_to_day::<JD>(time.to_j2000s().raw_j2000_seconds())
62    }
63
64    #[inline]
65    fn into_time(raw: Day) -> Time<S, Self> {
66        Time::<S, J2000s>::from_raw_j2000_seconds(day_to_j2000_seconds::<JD>(raw))
67            .expect("finite Julian date must decode")
68            .reinterpret()
69    }
70}
71
72impl<S: CoordinateScale> FormatForScale<S> for MJD {
73    #[inline]
74    fn try_from_time<Fin: TimeFormat>(
75        time: Time<S, Fin>,
76        _ctx: &TimeContext,
77    ) -> Result<Day, ConversionError> {
78        Ok(<Self as InfallibleFormatForScale<S>>::from_time(time))
79    }
80
81    #[inline]
82    fn try_into_time(raw: Day, _ctx: &TimeContext) -> Result<Time<S, Self>, ConversionError> {
83        Ok(<Self as InfallibleFormatForScale<S>>::into_time(raw))
84    }
85}
86
87impl<S: CoordinateScale> InfallibleFormatForScale<S> for MJD {
88    #[inline]
89    fn from_time<Fin: TimeFormat>(time: Time<S, Fin>) -> Day {
90        j2000_seconds_to_day::<MJD>(time.to_j2000s().raw_j2000_seconds())
91    }
92
93    #[inline]
94    fn into_time(raw: Day) -> Time<S, Self> {
95        Time::<S, J2000s>::from_raw_j2000_seconds(day_to_j2000_seconds::<MJD>(raw))
96            .expect("finite Modified Julian date must decode")
97            .reinterpret()
98    }
99}
100
101impl FormatForScale<UTC> for Unix {
102    #[inline]
103    fn try_from_time<Fin: TimeFormat>(
104        time: Time<UTC, Fin>,
105        ctx: &TimeContext,
106    ) -> Result<Second, ConversionError> {
107        time.to_j2000s().raw_unix_seconds_with(ctx)
108    }
109
110    #[inline]
111    fn try_into_time(raw: Second, ctx: &TimeContext) -> Result<Time<UTC, Self>, ConversionError> {
112        Time::<UTC, J2000s>::from_raw_unix_seconds_with(raw, ctx).map(|t| t.reinterpret())
113    }
114}
115
116impl FormatForScale<TAI> for GPS {
117    #[inline]
118    fn try_from_time<Fin: TimeFormat>(
119        time: Time<TAI, Fin>,
120        _ctx: &TimeContext,
121    ) -> Result<Second, ConversionError> {
122        Ok(<Self as InfallibleFormatForScale<TAI>>::from_time(time))
123    }
124
125    #[inline]
126    fn try_into_time(raw: Second, _ctx: &TimeContext) -> Result<Time<TAI, Self>, ConversionError> {
127        Ok(<Self as InfallibleFormatForScale<TAI>>::into_time(raw))
128    }
129}
130
131impl InfallibleFormatForScale<TAI> for GPS {
132    #[inline]
133    fn from_time<Fin: TimeFormat>(time: Time<TAI, Fin>) -> Second {
134        time.to_j2000s().raw_gps_seconds()
135    }
136
137    #[inline]
138    fn into_time(raw: Second) -> Time<TAI, Self> {
139        Time::<TAI, J2000s>::from_raw_gps_seconds(raw)
140            .expect("finite GPS seconds must decode")
141            .reinterpret()
142    }
143}