From ebb5721e98aca70c742f7d2ab7a4b506f324bbb9 Mon Sep 17 00:00:00 2001 From: Helge Eichhorn Date: Tue, 9 Jul 2024 06:18:03 +0200 Subject: [PATCH] WIP --- crates/lox-time/src/python/time.rs | 22 +++++++++++------ crates/lox-time/src/time_scales.rs | 39 ++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/crates/lox-time/src/python/time.rs b/crates/lox-time/src/python/time.rs index fe210b55..8dbbad36 100644 --- a/crates/lox-time/src/python/time.rs +++ b/crates/lox-time/src/python/time.rs @@ -16,6 +16,7 @@ use pyo3::{pyclass, pymethods, Bound, PyAny, PyErr, PyObject, PyResult, Python}; use lox_utils::is_close::IsClose; +use super::ut1::PyNoOpOffsetProvider; use crate::calendar_dates::{CalendarDate, Date}; use crate::deltas::{TimeDelta, ToDelta}; use crate::julian_dates::{Epoch, JulianDate, Unit}; @@ -26,11 +27,16 @@ use crate::python::ut1::{PyDeltaUt1Provider, PyUt1Provider}; use crate::python::utc::PyUtc; use crate::subsecond::{InvalidSubsecond, Subsecond}; use crate::time_of_day::TimeOfDay; +use crate::time_scales::{DynTimeScale, InvalidTimeScale}; use crate::transformations::{ToTai, ToTcb, ToTcg, ToTdb, ToTt, TryToScale}; use crate::utc::transformations::ToUtc; -use crate::{Time, TimeError, TimeLike}; +use crate::{DynTime, Time, TimeError, TimeLike}; -use super::ut1::PyNoOpOffsetProvider; +impl From for PyErr { + fn from(value: InvalidTimeScale) -> Self { + PyValueError::new_err(value.to_string()) + } +} impl From for PyErr { fn from(value: InvalidSubsecond) -> Self { @@ -73,7 +79,7 @@ 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(crate) DynTime); #[pymethods] impl PyTime { @@ -88,7 +94,7 @@ impl PyTime { minute: u8, seconds: f64, ) -> PyResult { - let scale: PyTimeScale = scale.parse()?; + let scale: DynTimeScale = scale.parse()?; let time = Time::builder_with_scale(scale) .with_ymd(year, month, day) .with_hms(hour, minute, seconds) @@ -104,18 +110,18 @@ impl PyTime { jd: f64, epoch: &str, ) -> PyResult { - let scale: PyTimeScale = scale.parse()?; + let scale: DynTimeScale = scale.parse()?; let epoch: Epoch = epoch.parse()?; Ok(Self(Time::from_julian_date(scale, jd, epoch)?)) } #[classmethod] pub fn from_iso(_cls: &Bound<'_, PyType>, iso: &str, scale: Option<&str>) -> PyResult { - let scale: PyTimeScale = match scale { + let scale: DynTimeScale = match scale { Some(scale) => scale.parse()?, None => match iso.split_once(char::is_whitespace) { Some((_, scale)) => scale.parse()?, - None => PyTimeScale::Tai, + None => DynTimeScale::Tai, }, }; let time = Time::from_iso(scale, iso)?; @@ -129,7 +135,7 @@ impl PyTime { seconds: i64, subsecond: f64, ) -> PyResult { - let scale: PyTimeScale = scale.parse()?; + let scale: DynTimeScale = scale.parse()?; let subsecond = Subsecond::new(subsecond)?; let time = Time::new(scale, seconds, subsecond); Ok(PyTime(time)) diff --git a/crates/lox-time/src/time_scales.rs b/crates/lox-time/src/time_scales.rs index 8431dd2c..5ff37f87 100644 --- a/crates/lox-time/src/time_scales.rs +++ b/crates/lox-time/src/time_scales.rs @@ -16,6 +16,10 @@ exclusively as an IO format. */ +use std::str::FromStr; + +use thiserror::Error; + pub mod transformations; /// Marker trait denoting a continuous astronomical time scale. @@ -136,6 +140,26 @@ impl TimeScale for DynTimeScale { } } +#[derive(Error, Debug, Clone, Eq, PartialEq, PartialOrd, Ord)] +#[error("invalid time scale: {0}")] +pub struct InvalidTimeScale(String); + +impl FromStr for DynTimeScale { + type Err = InvalidTimeScale; + + fn from_str(name: &str) -> Result { + match name { + "TAI" => Ok(DynTimeScale::Tai), + "TCB" => Ok(DynTimeScale::Tcb), + "TCG" => Ok(DynTimeScale::Tcg), + "TDB" => Ok(DynTimeScale::Tdb), + "TT" => Ok(DynTimeScale::Tt), + "UT1" => Ok(DynTimeScale::Ut1), + _ => Err(InvalidTimeScale(name.to_string())), + } + } +} + #[cfg(test)] mod tests { use super::*; @@ -156,4 +180,19 @@ mod tests { assert_eq!(scale.abbreviation(), abbreviation); assert_eq!(scale.name(), name); } + + #[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_dyn_time_scale(#[case] abbreviation: &'static str, #[case] name: &'static str) { + let scale = DynTimeScale::from_str(abbreviation).unwrap(); + assert_eq!(scale.abbreviation(), abbreviation); + assert_eq!(scale.name(), name); + } }