From f085b12fb8fd3fa4d7294a4bf8716e972e27ec4e Mon Sep 17 00:00:00 2001 From: Helge Eichhorn Date: Sun, 5 Jan 2025 20:36:30 +0100 Subject: [PATCH] WIP --- crates/lox-orbits/src/analysis.rs | 2 - crates/lox-time/src/lib.rs | 33 +++- crates/lox-time/src/python/time.rs | 62 +++--- crates/lox-time/src/python/time_scales.rs | 96 ++-------- crates/lox-time/src/time_scales.rs | 2 +- crates/lox-time/src/time_scales/offsets.rs | 2 +- crates/lox-time/src/utc/transformations.rs | 208 +++++---------------- 7 files changed, 128 insertions(+), 277 deletions(-) diff --git a/crates/lox-orbits/src/analysis.rs b/crates/lox-orbits/src/analysis.rs index b1fe3268..37950f79 100644 --- a/crates/lox-orbits/src/analysis.rs +++ b/crates/lox-orbits/src/analysis.rs @@ -13,7 +13,6 @@ use lox_math::series::{Series, SeriesError}; use lox_math::types::units::Radians; use lox_time::deltas::TimeDelta; use lox_time::time_scales::Tdb; -use lox_time::transformations::TryToScale; use lox_time::TimeLike; use thiserror::Error; @@ -175,7 +174,6 @@ mod tests { use lox_math::assert_close; use lox_math::is_close::IsClose; use lox_time::time_scales::Tai; - use lox_time::transformations::ToTai; use lox_time::utc::Utc; use lox_time::Time; use std::iter::zip; diff --git a/crates/lox-time/src/lib.rs b/crates/lox-time/src/lib.rs index ab5c419a..43615bc8 100644 --- a/crates/lox-time/src/lib.rs +++ b/crates/lox-time/src/lib.rs @@ -41,6 +41,7 @@ use std::str::FromStr; use itertools::Itertools; use lox_math::is_close::IsClose; use num::ToPrimitive; +use prelude::offsets::{FromScale, TryFromScale}; use thiserror::Error; use time_scales::offsets::TryToScale; @@ -309,6 +310,31 @@ impl Time { Time::new(scale, self.seconds, self.subsecond) } + pub fn try_from_scale( + scale: T, + time: Time, + provider: Option<&P>, + ) -> Result, T::Error> + where + S: TimeScale, + T: TimeScale + TryFromScale + Copy, + { + let dt = time.to_delta(); + Ok(Time::from_delta( + scale, + dt + scale.try_offset_from(time.scale, dt, provider)?, + )) + } + + pub fn from_scale(scale: T, time: Time) -> Time + where + S: TimeScale, + T: TimeScale + FromScale + Copy, + { + let dt = time.to_delta(); + Time::from_delta(scale, dt + scale.offset_from(time.scale, dt)) + } + pub fn try_to_scale( &self, scale: S, @@ -339,13 +365,6 @@ impl Time { Time::from_delta(scale, self.to_delta() + delta) } - pub fn to_delta(&self) -> TimeDelta { - TimeDelta { - seconds: self.seconds, - subsecond: self.subsecond, - } - } - /// Returns the Julian epoch as a [Time] in the given [TimeScale]. pub fn jd0(scale: T) -> Self { Self::from_epoch(scale, Epoch::JulianDate) diff --git a/crates/lox-time/src/python/time.rs b/crates/lox-time/src/python/time.rs index 0b48858f..496f994c 100644 --- a/crates/lox-time/src/python/time.rs +++ b/crates/lox-time/src/python/time.rs @@ -19,7 +19,7 @@ use lox_math::is_close::IsClose; use crate::calendar_dates::{CalendarDate, Date}; use crate::deltas::{TimeDelta, ToDelta}; use crate::julian_dates::{Epoch, JulianDate, Unit}; -use crate::prelude::{CivilTime, Tai, Tcb, Tcg, Tdb, TimeScale, Tt, Ut1}; +use crate::prelude::{CivilTime, DynTimeScale, Tai, Tcb, Tcg, Tdb, TimeScale, Tt, Ut1}; use crate::python::deltas::PyTimeDelta; use crate::python::time_scales::PyTimeScale; use crate::python::ut1::{PyDeltaUt1Provider, PyUt1Provider}; @@ -27,7 +27,7 @@ use crate::python::utc::PyUtc; use crate::subsecond::{InvalidSubsecond, Subsecond}; use crate::time_of_day::TimeOfDay; use crate::utc::transformations::ToUtc; -use crate::{Time, TimeError, TimeLike}; +use crate::{DynTime, Time, TimeError, TimeLike}; use super::ut1::PyNoOpOffsetProvider; @@ -72,14 +72,14 @@ impl FromStr for Unit { #[pyclass(name = "Time", module = "lox_space", frozen)] #[derive(Clone, Debug, Eq, PartialEq)] -pub struct PyTime(pub Time); +pub struct PyTime(pub DynTime); #[pymethods] impl PyTime { #[new] #[pyo3(signature=(scale, year, month, day, hour = 0, minute = 0, seconds = 0.0))] pub fn new( - scale: &str, + scale: &Bound<'_, PyAny>, year: i64, month: u8, day: u8, @@ -87,7 +87,7 @@ impl PyTime { minute: u8, seconds: f64, ) -> PyResult { - let scale: PyTimeScale = scale.parse()?; + let scale: DynTimeScale = scale.try_into()?; let time = Time::builder_with_scale(scale) .with_ymd(year, month, day) .with_hms(hour, minute, seconds) @@ -99,11 +99,11 @@ impl PyTime { #[pyo3(signature = (scale, jd, epoch = "jd"))] pub fn from_julian_date( _cls: &Bound<'_, PyType>, - scale: &str, + scale: &Bound<'_, PyAny>, jd: f64, epoch: &str, ) -> PyResult { - let scale: PyTimeScale = scale.parse()?; + let scale: DynTimeScale = scale.try_into()?; let epoch: Epoch = epoch.parse()?; Ok(Self(Time::from_julian_date(scale, jd, epoch)?)) } @@ -111,11 +111,11 @@ impl PyTime { #[classmethod] pub fn from_two_part_julian_date( _cls: &Bound<'_, PyType>, - scale: &str, + scale: &Bound<'_, PyAny>, jd1: f64, jd2: f64, ) -> PyResult { - let scale: PyTimeScale = scale.parse()?; + let scale: DynTimeScale = scale.try_into()?; Ok(Self(Time::from_two_part_julian_date(scale, jd1, jd2)?)) } @@ -123,14 +123,14 @@ impl PyTime { #[pyo3(signature=(scale, year, day, hour=0, minute=0, seconds=0.0))] pub fn from_day_of_year( _cls: &Bound<'_, PyType>, - scale: &str, + scale: &Bound<'_, PyAny>, year: i64, day: u16, hour: u8, minute: u8, seconds: f64, ) -> PyResult { - let scale: PyTimeScale = scale.parse()?; + let scale: DynTimeScale = scale.try_into()?; let time = Time::builder_with_scale(scale) .with_doy(year, day) .with_hms(hour, minute, seconds) @@ -140,14 +140,13 @@ impl PyTime { #[classmethod] #[pyo3(signature = (iso, scale=None))] - pub fn from_iso(_cls: &Bound<'_, PyType>, iso: &str, scale: Option<&str>) -> PyResult { - let scale: PyTimeScale = match scale { - Some(scale) => scale.parse()?, - None => match iso.split_once(char::is_whitespace) { - Some((_, scale)) => scale.parse()?, - None => PyTimeScale::Tai, - }, - }; + pub fn from_iso( + _cls: &Bound<'_, PyType>, + iso: &str, + scale: Option<&Bound<'_, PyAny>>, + ) -> PyResult { + let scale: DynTimeScale = + scale.map_or(Ok(DynTimeScale::default()), |scale| scale.try_into())?; let time = Time::from_iso(scale, iso)?; Ok(PyTime(time)) } @@ -155,11 +154,11 @@ impl PyTime { #[classmethod] pub fn from_seconds( _cls: &Bound<'_, PyType>, - scale: &str, + scale: &Bound<'_, PyAny>, seconds: i64, subsecond: f64, ) -> PyResult { - let scale: PyTimeScale = scale.parse()?; + let scale: DynTimeScale = scale.try_into()?; let subsecond = Subsecond::new(subsecond)?; let time = Time::new(scale, seconds, subsecond); Ok(PyTime(time)) @@ -504,7 +503,7 @@ impl IsClose for PyTime { #[cfg(test)] mod tests { use float_eq::assert_float_eq; - use pyo3::{types::PyDict, Python}; + use pyo3::{types::PyDict, IntoPyObjectExt, Python}; use lox_math::assert_close; @@ -512,9 +511,15 @@ mod tests { use super::*; + fn py_tai<'py>(py: Python<'py>) -> Bound<'py, PyAny> { + "TAI".into_bound_py_any(py).unwrap() + } + #[test] fn test_pytime() { - let time = PyTime::new("TAI", 2000, 1, 1, 0, 0, 12.123456789123).unwrap(); + let time = Python::with_gil(|py| { + PyTime::new(&py_tai(py), 2000, 1, 1, 0, 0, 12.123456789123).unwrap() + }); assert_eq!( time.__repr__(), "Time(\"TAI\", 2000, 1, 1, 0, 0, 12.123456789123)" @@ -538,28 +543,29 @@ mod tests { #[test] #[should_panic(expected = "invalid date")] fn test_pytime_invalid_date() { - PyTime::new("TAI", 2000, 13, 1, 0, 0, 0.0).unwrap(); + Python::with_gil(|py| PyTime::new(&py_tai(py), 2000, 13, 1, 0, 0, 0.0).unwrap()); } #[test] #[should_panic(expected = "hour must be in the range")] fn test_pytime_invalid_time() { - PyTime::new("TAI", 2000, 12, 1, 24, 0, 0.0).unwrap(); + Python::with_gil(|py| PyTime::new(&py_tai(py), 2000, 12, 1, 24, 0, 0.0).unwrap()); } #[test] fn test_pytime_ops() { Python::with_gil(|py| { - let t0 = PyTime::new("TAI", 2000, 1, 1, 0, 0, 0.0).unwrap(); + let t0 = PyTime::new(&py_tai(py), 2000, 1, 1, 0, 0, 0.0).unwrap(); let dt = PyTimeDelta::new(1.0).unwrap(); - let t1 = PyTime::new("TAI", 2000, 1, 1, 0, 0, 1.0).unwrap(); + let t1 = PyTime::new(&py_tai(py), 2000, 1, 1, 0, 0, 1.0).unwrap(); assert_eq!(t0.__add__(dt.clone()), t1.clone()); let dtb = Bound::new(py, PyTimeDelta::new(1.0).unwrap()).unwrap(); assert_eq!( t1.__sub__(py, &dtb).unwrap().extract::().unwrap(), t0 ); - let t0b = Bound::new(py, PyTime::new("TAI", 2000, 1, 1, 0, 0, 0.0).unwrap()).unwrap(); + let t0b = + Bound::new(py, PyTime::new(&py_tai(py), 2000, 1, 1, 0, 0, 0.0).unwrap()).unwrap(); assert_eq!( t1.__sub__(py, &t0b) .unwrap() diff --git a/crates/lox-time/src/python/time_scales.rs b/crates/lox-time/src/python/time_scales.rs index 9d8c2f2b..b710f974 100644 --- a/crates/lox-time/src/python/time_scales.rs +++ b/crates/lox-time/src/python/time_scales.rs @@ -6,89 +6,31 @@ * file, you can obtain one at https://mozilla.org/MPL/2.0/. */ -use crate::prelude::{Tai, Tcb, Tcg, Tdb, TimeScale, Tt, Ut1}; -use pyo3::exceptions::PyValueError; -use pyo3::PyErr; -use std::fmt::{Display, Formatter}; -use std::str::FromStr; +use pyo3::{exceptions::PyValueError, pyclass, types::PyAnyMethods, Bound, PyAny, PyErr}; -#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] -pub enum PyTimeScale { - Tai, - Tcb, - Tcg, - Tdb, - Tt, - Ut1, -} +use crate::prelude::{DynTimeScale, UnknownTimeScaleError}; -impl FromStr for PyTimeScale { - type Err = PyErr; - - fn from_str(name: &str) -> Result { - match name { - "TAI" => Ok(PyTimeScale::Tai), - "TCB" => Ok(PyTimeScale::Tcb), - "TCG" => Ok(PyTimeScale::Tcg), - "TDB" => Ok(PyTimeScale::Tdb), - "TT" => Ok(PyTimeScale::Tt), - "UT1" => Ok(PyTimeScale::Ut1), - _ => Err(PyValueError::new_err(format!( - "invalid time scale: {}", - name - ))), - } +impl From for PyErr { + fn from(err: UnknownTimeScaleError) -> Self { + PyValueError::new_err(err.to_string()) } } -impl TimeScale for PyTimeScale { - fn abbreviation(&self) -> &'static str { - match self { - PyTimeScale::Tai => Tai.abbreviation(), - PyTimeScale::Tcb => Tcb.abbreviation(), - PyTimeScale::Tcg => Tcg.abbreviation(), - PyTimeScale::Tdb => Tdb.abbreviation(), - PyTimeScale::Tt => Tt.abbreviation(), - PyTimeScale::Ut1 => Ut1.abbreviation(), - } - } - - fn name(&self) -> &'static str { - match self { - PyTimeScale::Tai => Tai.name(), - PyTimeScale::Tcb => Tcb.name(), - PyTimeScale::Tcg => Tcg.name(), - PyTimeScale::Tdb => Tdb.name(), - PyTimeScale::Tt => Tt.name(), - PyTimeScale::Ut1 => Ut1.name(), - } - } -} - -impl Display for PyTimeScale { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.abbreviation()) - } -} +#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] +#[pyclass] +pub struct PyTimeScale(pub DynTimeScale); -#[cfg(test)] -mod tests { - use super::*; - use rstest::rstest; +impl TryFrom<&Bound<'_, PyAny>> for DynTimeScale { + type Error = PyErr; - #[rstest] - #[case("TAI", "International Atomic Time")] - #[case("TT", "Terrestrial Time")] - #[case("TCG", "Geocentric Coordinate Time")] - #[case("TCB", "Barycentric Coordinate Time")] - #[case("TDB", "Barycentric Dynamical Time")] - #[case("UT1", "Universal Time")] - #[should_panic(expected = "invalid time scale: NotATimeScale")] - #[case("NotATimeScale", "not a time scale")] - fn test_pytimescale(#[case] abbreviation: &'static str, #[case] name: &'static str) { - let scale = PyTimeScale::from_str(abbreviation).unwrap(); - assert_eq!(scale.abbreviation(), abbreviation); - assert_eq!(scale.name(), name); - assert_eq!(scale.to_string(), abbreviation); + fn try_from(value: &Bound<'_, PyAny>) -> Result { + if let Ok(name) = value.extract::<&str>() { + return Ok(name.parse()?); + } else if let Ok(scale) = value.extract::() { + return Ok(scale.0); + } + Err(PyValueError::new_err( + "'scale' argument must either a string or a 'TimeScale' instance", + )) } } diff --git a/crates/lox-time/src/time_scales.rs b/crates/lox-time/src/time_scales.rs index fbf9f8c1..d70eeaba 100644 --- a/crates/lox-time/src/time_scales.rs +++ b/crates/lox-time/src/time_scales.rs @@ -144,10 +144,10 @@ impl Display for Ut1 { #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] pub enum DynTimeScale { + #[default] Tai, Tcb, Tcg, - #[default] Tdb, Tt, Ut1, diff --git a/crates/lox-time/src/time_scales/offsets.rs b/crates/lox-time/src/time_scales/offsets.rs index 497ee0d4..559ccf13 100644 --- a/crates/lox-time/src/time_scales/offsets.rs +++ b/crates/lox-time/src/time_scales/offsets.rs @@ -51,7 +51,7 @@ pub trait ToScale { fn offset(&self, scale: T, dt: TimeDelta) -> TimeDelta; } -trait FromScale { +pub trait FromScale { fn offset_from(&self, scale: T, dt: TimeDelta) -> TimeDelta; } diff --git a/crates/lox-time/src/utc/transformations.rs b/crates/lox-time/src/utc/transformations.rs index 62761fed..c079ffa8 100644 --- a/crates/lox-time/src/utc/transformations.rs +++ b/crates/lox-time/src/utc/transformations.rs @@ -6,25 +6,16 @@ * file, you can obtain one at https://mozilla.org/MPL/2.0/. */ -use std::convert::Infallible; use std::sync::OnceLock; -use thiserror::Error; - use crate::deltas::TimeDelta; use crate::deltas::ToDelta; -use crate::prelude::offsets::ToScale; -use crate::prelude::offsets::TryFromScale; use crate::prelude::TimeScale; use crate::time_of_day::CivilTime; use crate::time_of_day::TimeOfDay; -use crate::time_scales::Tai; -use crate::time_scales::Tcb; -use crate::time_scales::Tcg; -use crate::time_scales::Tdb; -use crate::time_scales::Tt; -use crate::time_scales::Ut1; -use crate::ut1::DeltaUt1TaiProvider; +use crate::time_scales::offsets::{FromScale, ToScale, TryFromScale}; +use crate::time_scales::{DynTimeScale, Tai}; +use crate::DynTime; use crate::{utc, Time}; use super::leap_seconds::BuiltinLeapSeconds; @@ -33,37 +24,46 @@ use super::{Utc, UtcError}; mod before1972; -#[derive(Clone, Debug, Error, Eq, PartialEq)] -enum UtcTransformationError { - #[error(transparent)] - UtcError(#[from] UtcError), - #[error(transparent)] - TransformationError(#[from] E), -} - impl Utc { - pub fn try_to_scale, L: LeapSecondsProvider, P>( - &self, - scale: T, - ls_provider: Option<&L>, - provider: Option<&P>, - ) -> Result, UtcTransformationError<>::Error>> { - let delta = if self < utc_1972_01_01() { + pub fn offset_tai(&self, provider: &impl LeapSecondsProvider) -> TimeDelta { + if self < utc_1972_01_01() { before1972::delta_utc_tai(self) } else { - ls_provider - .map(|p| p.delta_utc_tai(*self)) - .unwrap_or(BuiltinLeapSeconds.delta_utc_tai(*self)) + provider.delta_utc_tai(*self) } - .unwrap_or_else(|| { - // Utc objects are always in range. - unreachable!("failed to calculate UTC-TAI delta for Utc `{:?}`", self); - }); + .expect("Utc objects should always be in range") + } - let tai = self.to_delta() - delta; - let offset = scale.try_offset_from(Tai, tai, provider)?; + pub fn to_time_with_provider(&self, provider: &impl LeapSecondsProvider) -> Time { + let offset = self.offset_tai(provider); + Time::from_delta(Tai, self.to_delta() + offset) + } + + pub fn to_time(&self) -> Time { + self.to_time_with_provider(&BuiltinLeapSeconds) + } + + pub fn to_dyn_time_with_provider(&self, provider: &impl LeapSecondsProvider) -> DynTime { + let offset = self.offset_tai(provider); + Time::from_delta(DynTimeScale::Tai, self.to_delta() + offset) + } - Ok(Time::from_delta(scale, tai + offset)) + pub fn to_dyn_time(&self) -> DynTime { + self.to_dyn_time_with_provider(&BuiltinLeapSeconds) + } + + pub fn try_to_scale(&self, scale: T, provider: Option<&P>) -> Result, T::Error> + where + T: TimeScale + TryFromScale + Copy, + { + Time::try_from_scale(scale, self.to_time(), provider) + } + + pub fn to_scale(&self, scale: T) -> Time + where + T: TimeScale + FromScale + Copy, + { + Time::from_scale(scale, self.to_time()) } } @@ -81,11 +81,8 @@ impl ToUtc for Utc { } } -impl> Time { - pub fn to_utc_with_provider( - &self, - provider: &impl LeapSecondsProvider, - ) -> Result { +impl> ToUtc for Time { + fn to_utc_with_provider(&self, provider: &impl LeapSecondsProvider) -> Result { let tai = self.to_scale(Tai); let delta = if &tai < tai_at_utc_1972_01_01() { before1972::delta_tai_utc(&tai) @@ -101,120 +98,8 @@ impl> Time { } Ok(utc) } - - pub fn to_utc(&self) -> Result { - self.to_utc_with_provider(&BuiltinLeapSeconds) - } } -// impl ToUtc for Time { -// fn to_utc_with_provider(&self, provider: &impl LeapSecondsProvider) -> Result { -// self.to_tai().to_utc_with_provider(provider) -// } -// } -// -// impl ToUtc for Time { -// fn to_utc_with_provider(&self, provider: &impl LeapSecondsProvider) -> Result { -// self.to_tai().to_utc_with_provider(provider) -// } -// } -// -// impl ToUtc for Time { -// fn to_utc_with_provider(&self, provider: &impl LeapSecondsProvider) -> Result { -// self.to_tai().to_utc_with_provider(provider) -// } -// } -// -// impl ToUtc for Time { -// fn to_utc_with_provider(&self, provider: &impl LeapSecondsProvider) -> Result { -// self.to_tai().to_utc_with_provider(provider) -// } -// } -// -// impl TryToScale for Utc { -// fn try_to_scale(&self, _scale: Tai, provider: &T) -> Result, T::Error> { -// let delta = if self < utc_1972_01_01() { -// before1972::delta_utc_tai(self) -// } else { -// provider.delta_utc_tai(*self) -// } -// .unwrap_or_else(|| { -// // Utc objects are always in range. -// unreachable!("failed to calculate UTC-TAI delta for Utc `{:?}`", self); -// }); -// -// Ok(Time::from_delta(Tai, self.to_delta() - delta)) -// } -// } -// -// impl TryToScale for Utc { -// fn try_to_scale( -// &self, -// scale: Tai, -// _provider: &NoOpOffsetProvider, -// ) -> Result, Infallible> { -// self.try_to_scale(scale, &BuiltinLeapSeconds) -// } -// } -// -// impl ToTai for Utc {} -// -// impl TryToScale for Utc { -// fn try_to_scale( -// &self, -// scale: Tt, -// provider: &NoOpOffsetProvider, -// ) -> Result, Infallible> { -// self.to_tai().try_to_scale(scale, provider) -// } -// } -// -// impl ToTt for Utc {} -// -// impl TryToScale for Utc { -// fn try_to_scale( -// &self, -// scale: Tdb, -// provider: &NoOpOffsetProvider, -// ) -> Result, Infallible> { -// self.to_tt().try_to_scale(scale, provider) -// } -// } -// -// impl ToTdb for Utc {} -// -// impl TryToScale for Utc { -// fn try_to_scale( -// &self, -// scale: Tcb, -// provider: &NoOpOffsetProvider, -// ) -> Result, Infallible> { -// self.to_tdb().try_to_scale(scale, provider) -// } -// } -// -// impl ToTcb for Utc {} -// -// impl TryToScale for Utc { -// fn try_to_scale( -// &self, -// scale: Tcg, -// provider: &NoOpOffsetProvider, -// ) -> Result, Infallible> { -// self.to_tt().try_to_scale(scale, provider) -// } -// } -// -// impl ToTcg for Utc {} -// -// impl TryToScale for Utc { -// fn try_to_scale(&self, scale: Ut1, provider: &T) -> Result, T::Error> { -// self.to_tai().try_to_scale(scale, provider) -// } -// } - -// impl ToUt1 for Utc {} - fn utc_1972_01_01() -> &'static Utc { static UTC_1972: OnceLock = OnceLock::new(); UTC_1972.get_or_init(|| utc!(1972, 1, 1).unwrap()) @@ -233,6 +118,7 @@ fn tai_at_utc_1972_01_01() -> &'static Time { #[cfg(test)] mod test { + use crate::prelude::{Tcb, Tcg, Tdb, Tt, Ut1}; use crate::test_helpers::delta_ut1_tai; use crate::time; use rstest::rstest; @@ -256,7 +142,7 @@ mod test { #[should_panic] #[case::illegal_utc_datetime(unconstructable_utc_datetime(), &Time::new(Tai, 0, Subsecond::default()))] fn test_utc_to_tai(#[case] utc: &Utc, #[case] expected: &Time) { - let actual = utc.to_tai(); + let actual = utc.to_time(); assert_eq!(*expected, actual); } @@ -276,21 +162,21 @@ mod test { fn test_all_scales_to_utc() { let tai = time!(Tai, 2024, 5, 17, 12, 13, 14.0).unwrap(); let exp = tai.to_utc().unwrap(); - let tt = tai.to_tt(); + let tt = tai.to_scale(Tt); let act = tt.to_utc().unwrap(); assert_eq!(act, exp); - let tcg = tai.to_tcg(); + let tcg = tai.to_scale(Tcg); let act = tcg.to_utc().unwrap(); assert_eq!(act, exp); - let tcb = tai.to_tcb(); + let tcb = tai.to_scale(Tcb); let act = tcb.to_utc().unwrap(); assert_eq!(act, exp); - let tdb = tai.to_tdb(); + let tdb = tai.to_scale(Tdb); let act = tdb.to_utc().unwrap(); assert_eq!(act, exp); - let ut1 = tai.try_to_ut1(delta_ut1_tai()).unwrap(); + let ut1 = tai.try_to_scale(Ut1, Some(delta_ut1_tai())).unwrap(); let act = ut1 - .try_to_scale(Tai, delta_ut1_tai()) + .try_to_scale(Tai, Some(delta_ut1_tai())) .unwrap() .to_utc() .unwrap();