Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
helgee committed Jul 12, 2024
1 parent 89f1947 commit 5888ade
Show file tree
Hide file tree
Showing 11 changed files with 176 additions and 1,066 deletions.
102 changes: 76 additions & 26 deletions crates/lox-time/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ use crate::prelude::transformations::ToScale;
use crate::subsecond::Subsecond;
use crate::time_scales::transformations::{OffsetProvider, ToTai, TryToScale};
use crate::time_scales::{DynTimeScale, TimeScale};
use crate::utc::leap_seconds::BuiltinLeapSeconds;
use crate::utc::transformations::to_utc_with_provider;
use crate::utc::{LeapSecondsProvider, Utc, UtcError};

pub mod calendar_dates;
pub mod constants;
Expand All @@ -73,7 +76,6 @@ pub mod subsecond;
pub(crate) mod test_helpers;
pub mod time_of_day;
pub mod time_scales;
pub mod transformations;
pub mod ut1;
pub mod utc;

Expand Down Expand Up @@ -349,31 +351,79 @@ impl<T: TimeScale> Time<T> {
self.subsecond.into()
}

// pub fn try_to_scale<U, P>(&self, scale: U, provider: &P) -> Result<Time<U>, P::Error>
// where
// T: TryToScale<U, P>,
// U: TimeScale,
// P: OffsetProvider,
// {
// let delta = self.scale.try_to_scale(&scale, self.to_delta(), provider)?;
// Ok(Time::from_delta(scale, delta))
// }
//
// pub fn to_scale<U: TimeScale>(&self, scale: U) -> Time<U>
// where
// T: ToScale<U>,
// {
// let delta = self.scale.to_scale(&scale, self.to_delta());
// Time::from_delta(scale, delta)
// }
//
// pub fn to_tai(&self) -> Time<Tai>
// where
// T: ToScale<Tai>,
// {
// let delta = self.scale.to_tai(self.to_delta());
// Time::from_delta(Tai, delta)
// }
pub fn try_to_scale<U, P>(&self, scale: U, provider: &P) -> Result<Time<U>, P::Error>
where
T: TryToScale<U, P>,
U: TimeScale,
P: OffsetProvider,
{
let delta = self.scale.try_to_scale(&scale, self.to_delta(), provider)?;
Ok(Time::from_delta(scale, delta))
}

pub fn to_scale<U: TimeScale>(&self, scale: U) -> Time<U>
where
T: ToScale<U>,
{
let delta = self.scale.to_scale(&scale, self.to_delta());
Time::from_delta(scale, delta)
}

pub fn to_tai(&self) -> Time<Tai>
where
T: ToScale<Tai>,
{
self.to_scale(Tai)
}

pub fn to_tcb(&self) -> Time<Tcb>
where
T: ToScale<Tcb>,
{
self.to_scale(Tcb)
}

pub fn to_tcg(&self) -> Time<Tcg>
where
T: ToScale<Tcg>,
{
self.to_scale(Tcg)
}

pub fn to_tdb(&self) -> Time<Tdb>
where
T: ToScale<Tdb>,
{
self.to_scale(Tdb)
}

pub fn to_tt(&self) -> Time<Tt>
where
T: ToScale<Tt>,
{
self.to_scale(Tt)
}

pub fn try_to_ut1<P: OffsetProvider>(&self, provider: &P) -> Result<Time<Ut1>, P::Error>
where
T: TryToScale<Ut1, P>,
{
self.try_to_scale(Ut1, provider)
}

pub fn to_utc_with_provider(&self, provider: &impl LeapSecondsProvider) -> Result<Utc, UtcError>
where
T: ToScale<Tai>,
{
to_utc_with_provider(self.to_tai(), provider)
}

pub fn to_utc(&self) -> Result<Utc, UtcError>
where
T: ToScale<Tai>,
{
self.to_utc_with_provider(&BuiltinLeapSeconds)
}
}

impl<T: TimeScale> IsClose for Time<T> {
Expand Down
143 changes: 24 additions & 119 deletions crates/lox-time/src/python/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,20 @@ 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};
use crate::prelude::{CivilTime, Tai, Tcb, Tcg, Tdb, TimeScale, Tt, Ut1};
use crate::prelude::{CivilTime, TimeScale};
use crate::python::deltas::PyTimeDelta;
use crate::python::time_scales::PyTimeScale;
use crate::python::ut1::{PyDeltaUt1Provider, PyUt1Provider};
use crate::python::ut1::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::{DynTime, Time, TimeError, TimeLike};

use super::ut1::PyNoOpOffsetProvider;

impl From<InvalidTimeScale> for PyErr {
fn from(value: InvalidTimeScale) -> Self {
PyValueError::new_err(value.to_string())
Expand Down Expand Up @@ -301,60 +299,45 @@ impl PyTime {
self.0.decimal_seconds()
}

pub fn to_tai(&self, provider: Option<&Bound<'_, PyUt1Provider>>) -> PyResult<PyTime> {
pub fn to_scale(
&self,
scale: &str,
provider: Option<&Bound<'_, PyUt1Provider>>,
) -> PyResult<PyTime> {
let scale: DynTimeScale = scale.parse()?;
let time = match provider {
Some(provider) => self.try_to_scale(Tai, provider.get())?,
None => self.try_to_scale(Tai, &PyNoOpOffsetProvider)?,
Some(provider) => self.0.try_to_scale(scale, provider.get())?,
None => self.0.try_to_scale(scale, &PyNoOpOffsetProvider)?,
};
Ok(PyTime(time.with_scale(PyTimeScale::Tai)))
Ok(PyTime(time))
}

pub fn to_tai(&self, provider: Option<&Bound<'_, PyUt1Provider>>) -> PyResult<PyTime> {
self.to_scale("TAI", provider)
}

pub fn to_tcb(&self, provider: Option<&Bound<'_, PyUt1Provider>>) -> PyResult<PyTime> {
let time = match provider {
Some(provider) => self.try_to_scale(Tcb, provider.get())?,
None => self.try_to_scale(Tcb, &PyNoOpOffsetProvider)?,
};
Ok(PyTime(time.with_scale(PyTimeScale::Tcb)))
self.to_scale("TCB", provider)
}

pub fn to_tcg(&self, provider: Option<&Bound<'_, PyUt1Provider>>) -> PyResult<PyTime> {
let time = match provider {
Some(provider) => self.try_to_scale(Tcg, provider.get())?,
None => self.try_to_scale(Tcg, &PyNoOpOffsetProvider)?,
};
Ok(PyTime(time.with_scale(PyTimeScale::Tcg)))
self.to_scale("TCG", provider)
}

pub fn to_tdb(&self, provider: Option<&Bound<'_, PyUt1Provider>>) -> PyResult<PyTime> {
let time = match provider {
Some(provider) => self.try_to_scale(Tdb, provider.get())?,
None => self.try_to_scale(Tdb, &PyNoOpOffsetProvider)?,
};
Ok(PyTime(time.with_scale(PyTimeScale::Tdb)))
self.to_scale("TDB", provider)
}

pub fn to_tt(&self, provider: Option<&Bound<'_, PyUt1Provider>>) -> PyResult<PyTime> {
let time = match provider {
Some(provider) => self.try_to_scale(Tt, provider.get())?,
None => self.try_to_scale(Tt, &PyNoOpOffsetProvider)?,
};
Ok(PyTime(time.with_scale(PyTimeScale::Tt)))
self.to_scale("TT", provider)
}

pub fn to_ut1(&self, provider: Option<&Bound<'_, PyUt1Provider>>) -> PyResult<PyTime> {
let time = match provider {
Some(provider) => self.try_to_scale(Ut1, provider.get())?,
None => self.try_to_scale(Ut1, &PyNoOpOffsetProvider)?,
};
Ok(PyTime(time.with_scale(PyTimeScale::Ut1)))
self.to_scale("TAI", provider)
}

pub fn to_utc(&self, provider: Option<&Bound<'_, PyUt1Provider>>) -> PyResult<PyUtc> {
let tai = match provider {
Some(provider) => self.try_to_scale(Tai, provider.get())?,
None => self.try_to_scale(Tai, &PyNoOpOffsetProvider)?,
};
Ok(PyUtc(tai.to_utc()?))
pub fn to_utc(&self, _provider: Option<&Bound<'_, PyUt1Provider>>) -> PyResult<PyUtc> {
todo!()
}
}

Expand Down Expand Up @@ -408,84 +391,6 @@ impl CivilTime for PyTime {

impl TimeLike for PyTime {}

impl<T: PyDeltaUt1Provider> TryToScale<Tai, T> for PyTime {
fn try_to_scale(&self, _scale: Tai, provider: &T) -> PyResult<Time<Tai>> {
match self.0.scale() {
PyTimeScale::Tai => Ok(self.0.with_scale(Tai)),
PyTimeScale::Tcb => Ok(self.0.with_scale(Tcb).to_tai()),
PyTimeScale::Tcg => Ok(self.0.with_scale(Tcg).to_tai()),
PyTimeScale::Tdb => Ok(self.0.with_scale(Tdb).to_tai()),
PyTimeScale::Tt => Ok(self.0.with_scale(Tt).to_tai()),
PyTimeScale::Ut1 => self.0.with_scale(Ut1).try_to_scale(Tai, provider),
}
}
}

impl<T: PyDeltaUt1Provider> TryToScale<Tcg, T> for PyTime {
fn try_to_scale(&self, _scale: Tcg, provider: &T) -> PyResult<Time<Tcg>> {
match self.0.scale() {
PyTimeScale::Tai => Ok(self.0.with_scale(Tai).to_tcg()),
PyTimeScale::Tcb => Ok(self.0.with_scale(Tcb).to_tcg()),
PyTimeScale::Tcg => Ok(self.0.with_scale(Tcg)),
PyTimeScale::Tdb => Ok(self.0.with_scale(Tdb).to_tcg()),
PyTimeScale::Tt => Ok(self.0.with_scale(Tt).to_tcg()),
PyTimeScale::Ut1 => self.0.with_scale(Ut1).try_to_scale(Tcg, provider),
}
}
}

impl<T: PyDeltaUt1Provider> TryToScale<Tcb, T> for PyTime {
fn try_to_scale(&self, _scale: Tcb, provider: &T) -> PyResult<Time<Tcb>> {
match self.0.scale() {
PyTimeScale::Tai => Ok(self.0.with_scale(Tai).to_tcb()),
PyTimeScale::Tcb => Ok(self.0.with_scale(Tcb)),
PyTimeScale::Tcg => Ok(self.0.with_scale(Tcg).to_tcb()),
PyTimeScale::Tdb => Ok(self.0.with_scale(Tdb).to_tcb()),
PyTimeScale::Tt => Ok(self.0.with_scale(Tt).to_tcb()),
PyTimeScale::Ut1 => self.0.with_scale(Ut1).try_to_scale(Tcb, provider),
}
}
}

impl<T: PyDeltaUt1Provider> TryToScale<Tdb, T> for PyTime {
fn try_to_scale(&self, _scale: Tdb, provider: &T) -> Result<Time<Tdb>, T::Error> {
match self.0.scale() {
PyTimeScale::Tai => Ok(self.0.with_scale(Tai).to_tdb()),
PyTimeScale::Tcb => Ok(self.0.with_scale(Tcb).to_tdb()),
PyTimeScale::Tcg => Ok(self.0.with_scale(Tcg).to_tdb()),
PyTimeScale::Tdb => Ok(self.0.with_scale(Tdb)),
PyTimeScale::Tt => Ok(self.0.with_scale(Tt).to_tdb()),
PyTimeScale::Ut1 => self.0.with_scale(Ut1).try_to_scale(Tdb, provider),
}
}
}

impl<T: PyDeltaUt1Provider> TryToScale<Tt, T> for PyTime {
fn try_to_scale(&self, _scale: Tt, provider: &T) -> PyResult<Time<Tt>> {
match self.0.scale() {
PyTimeScale::Tai => Ok(self.0.with_scale(Tai).to_tt()),
PyTimeScale::Tcb => Ok(self.0.with_scale(Tcb).to_tt()),
PyTimeScale::Tcg => Ok(self.0.with_scale(Tcg).to_tt()),
PyTimeScale::Tdb => Ok(self.0.with_scale(Tdb).to_tt()),
PyTimeScale::Tt => Ok(self.0.with_scale(Tt)),
PyTimeScale::Ut1 => self.0.with_scale(Ut1).try_to_scale(Tt, provider),
}
}
}

impl<T: PyDeltaUt1Provider> TryToScale<Ut1, T> for PyTime {
fn try_to_scale(&self, _scale: Ut1, provider: &T) -> PyResult<Time<Ut1>> {
match self.0.scale() {
PyTimeScale::Tai => self.0.with_scale(Tai).try_to_scale(Ut1, provider),
PyTimeScale::Tcb => self.0.with_scale(Tcb).try_to_scale(Ut1, provider),
PyTimeScale::Tcg => self.0.with_scale(Tcg).try_to_scale(Ut1, provider),
PyTimeScale::Tdb => self.0.with_scale(Tdb).try_to_scale(Ut1, provider),
PyTimeScale::Tt => self.0.with_scale(Tt).try_to_scale(Ut1, provider),
PyTimeScale::Ut1 => Ok(self.0.with_scale(Ut1)),
}
}
}

impl IsClose for PyTime {
const DEFAULT_RELATIVE: f64 = 1e-10;

Expand Down
27 changes: 10 additions & 17 deletions crates/lox-time/src/python/ut1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*/

use pyo3::exceptions::PyValueError;
use pyo3::{pyclass, pymethods, PyErr, PyResult};

use crate::deltas::TimeDelta;
use crate::time_scales::{Tai, Ut1};
use crate::transformations::OffsetProvider;
use crate::time_scales::transformations::OffsetProvider;
use crate::ut1::{DeltaUt1Tai, DeltaUt1TaiError, DeltaUt1TaiProvider, ExtrapolatedDeltaUt1Tai};
use crate::utc::leap_seconds::BuiltinLeapSeconds;
use crate::Time;
use pyo3::exceptions::PyValueError;
use pyo3::{pyclass, pymethods, PyErr, PyResult};

impl From<ExtrapolatedDeltaUt1Tai> for PyErr {
fn from(value: ExtrapolatedDeltaUt1Tai) -> Self {
Expand All @@ -33,24 +32,20 @@ impl OffsetProvider for PyNoOpOffsetProvider {
type Error = PyErr;
}

pub trait PyDeltaUt1Provider: DeltaUt1TaiProvider + OffsetProvider<Error = PyErr> {}

impl DeltaUt1TaiProvider for PyNoOpOffsetProvider {
fn delta_ut1_tai(&self, _tai: &Time<Tai>) -> PyResult<TimeDelta> {
fn delta_ut1_tai(&self, _delta: TimeDelta) -> PyResult<TimeDelta> {
Err(PyValueError::new_err(
"`provider` argument needs to be present for UT1 transformations",
))
}

fn delta_tai_ut1(&self, _ut1: &Time<Ut1>) -> PyResult<TimeDelta> {
fn delta_tai_ut1(&self, _delta: TimeDelta) -> PyResult<TimeDelta> {
Err(PyValueError::new_err(
"`provider` argument needs to be present for UT1 transformations",
))
}
}

impl PyDeltaUt1Provider for PyNoOpOffsetProvider {}

#[pyclass(name = "UT1Provider", module = "lox_space", frozen)]
#[derive(Clone, Debug, PartialEq)]
pub struct PyUt1Provider(pub DeltaUt1Tai);
Expand All @@ -69,17 +64,15 @@ impl OffsetProvider for PyUt1Provider {
}

impl DeltaUt1TaiProvider for PyUt1Provider {
fn delta_ut1_tai(&self, tai: &Time<Tai>) -> PyResult<TimeDelta> {
self.0.delta_ut1_tai(tai).map_err(|err| err.into())
fn delta_ut1_tai(&self, delta: TimeDelta) -> PyResult<TimeDelta> {
self.0.delta_ut1_tai(delta).map_err(|err| err.into())
}

fn delta_tai_ut1(&self, ut1: &Time<Ut1>) -> PyResult<TimeDelta> {
self.0.delta_tai_ut1(ut1).map_err(|err| err.into())
fn delta_tai_ut1(&self, delta: TimeDelta) -> PyResult<TimeDelta> {
self.0.delta_tai_ut1(delta).map_err(|err| err.into())
}
}

impl PyDeltaUt1Provider for PyUt1Provider {}

#[cfg(test)]
mod tests {
use pyo3::{Bound, Python};
Expand Down
1 change: 0 additions & 1 deletion crates/lox-time/src/python/utc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use crate::prelude::CivilTime;
use crate::python::time::PyTime;
use crate::python::time_scales::PyTimeScale;
use crate::python::ut1::PyUt1Provider;
use crate::transformations::{ToTai, ToTcb, ToTcg, ToTdb, ToTt, ToUt1};
use crate::utc::{Utc, UtcError};
use pyo3::exceptions::PyValueError;
use pyo3::types::PyType;
Expand Down
Loading

0 comments on commit 5888ade

Please sign in to comment.