Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refine time representations #44

Merged
merged 14 commits into from
Jan 28, 2024
Merged
4 changes: 2 additions & 2 deletions crates/lox-space/examples/iss.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use lox_space::prelude::*;

fn main() {
let date = Date::new(2016, 5, 30).unwrap();
let time = Time::new(12, 0, 0).unwrap();
let epoch = Epoch::from_date_and_time(TimeScale::TDB, date, time);
let time = OldTime::new(12, 0, 0).unwrap();
let epoch = OldTime::from_date_and_time(TimeScale::TDB, date, time);
let position = DVec3::new(6068279.27, -1692843.94, -2516619.18) * 1e-3;
let velocity = DVec3::new(-660.415582, 5495.938726, -5303.093233) * 1e-3;
let iss = Cartesian::new(epoch, Earth, position, velocity);
Expand Down
14 changes: 7 additions & 7 deletions crates/lox_core/src/earth/nutation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::earth::nutation::iau2000::nutation_iau2000a;
use crate::earth::nutation::iau2000::nutation_iau2000b;
use crate::earth::nutation::iau2006::nutation_iau2006a;
use crate::math::RADIANS_IN_ARCSECOND;
use crate::time::epochs::Epoch;
use crate::time::continuous::Time;
use crate::time::intervals::tdb_julian_centuries_since_j2000;
use crate::types::Radians;

Expand Down Expand Up @@ -64,7 +64,7 @@ impl Add<&Self> for Nutation {
}

/// Calculate nutation coefficients at `epoch` using the given [Model].
pub fn nutation(model: Model, epoch: Epoch) -> Nutation {
pub fn nutation(model: Model, epoch: Time) -> Nutation {
let t = tdb_julian_centuries_since_j2000(epoch);
match model {
Model::IAU1980 => nutation_iau1980(t),
Expand Down Expand Up @@ -100,15 +100,15 @@ fn point1_microarcsec_to_rad(p1_uas: Point1Microarcsec) -> Radians {
mod tests {
use float_eq::assert_float_eq;

use crate::time::epochs::{Epoch, TimeScale};
use crate::time::scales::TimeScale;

use super::*;

const TOLERANCE: f64 = 1e-12;

#[test]
fn test_nutation_iau1980() {
let epoch = Epoch::j2000(TimeScale::TT);
let epoch = Time::j2000(TimeScale::TT);
let expected = Nutation {
longitude: -0.00006750247617532478,
obliquity: -0.00002799221238377013,
Expand All @@ -119,7 +119,7 @@ mod tests {
}
#[test]
fn test_nutation_iau2000a() {
let epoch = Epoch::j2000(TimeScale::TT);
let epoch = Time::j2000(TimeScale::TT);
let expected = Nutation {
longitude: -0.00006754422426417299,
obliquity: -0.00002797083119237414,
Expand All @@ -131,7 +131,7 @@ mod tests {

#[test]
fn test_nutation_iau2000b() {
let epoch = Epoch::j2000(TimeScale::TT);
let epoch = Time::j2000(TimeScale::TT);
let expected = Nutation {
longitude: -0.00006754261253992235,
obliquity: -0.00002797092331098565,
Expand All @@ -143,7 +143,7 @@ mod tests {

#[test]
fn test_nutation_iau2006a() {
let epoch = Epoch::j2000(TimeScale::TT);
let epoch = Time::j2000(TimeScale::TT);
let expected = Nutation {
longitude: -0.00006754425598969513,
obliquity: -0.00002797083119237414,
Expand Down
8 changes: 5 additions & 3 deletions crates/lox_core/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ pub enum LoxError {
#[error("invalid date `{0}-{1}-{2}`")]
InvalidDate(i64, i64, i64),
#[error("invalid time `{0}:{1}:{2}`")]
InvalidTime(i64, i64, i64),
#[error("invalid time `{0}:{1}:{2}`")]
InvalidSeconds(i64, i64, f64),
InvalidTime(u8, u8, u8),
#[error("seconds must be in the range [0.0, 60.0], but was `{0}`")]
InvalidSeconds(f64),
#[error("thousandths must be in the range [0, 999], but was `{0}`")]
InvalidThousandths(u16),
#[error("day of year cannot be 366 for a non-leap year")]
NonLeapYear,
}
79 changes: 78 additions & 1 deletion crates/lox_core/src/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,85 @@
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*/

use crate::errors::LoxError;
use crate::time::dates::Date;
use crate::time::scales::TimeScale;
use std::fmt::Display;

pub mod constants;
pub mod continuous;
pub mod dates;
pub mod epochs;
pub mod intervals;
pub mod leap_seconds;
pub mod scales;
pub mod utc;

/// `WallClock` is the trait by which high-precision time representations expose human-readable time components.
///
/// The components returned by a `WallClock` must be interpreted in terms of its [TimeScale]. For example, a UTC
/// `WallClock` will have a `second` component of 60 during a leap second.
pub trait WallClock {
fn scale(&self) -> TimeScale;
fn hour(&self) -> u8;
fn minute(&self) -> u8;
fn second(&self) -> u8;
fn millisecond(&self) -> Thousandths;
fn microsecond(&self) -> Thousandths;
fn nanosecond(&self) -> Thousandths;
fn picosecond(&self) -> Thousandths;
fn femtosecond(&self) -> Thousandths;
fn attosecond(&self) -> Thousandths;
}

/// Newtype wrapper for thousandths of an SI-prefixed subsecond (milli, micro, nano, etc.).
#[repr(transparent)]
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Thousandths(u16);

impl Thousandths {
pub fn new(thousandths: u16) -> Result<Self, LoxError> {
if !(0..1000).contains(&thousandths) {
Err(LoxError::InvalidThousandths(thousandths))
} else {
Ok(Self(thousandths))
}
}
}

impl Display for Thousandths {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:03}", self.0)
}
}

impl TryFrom<u16> for Thousandths {
type Error = LoxError;

fn try_from(thousandths: u16) -> Result<Self, Self::Error> {
Self::new(thousandths)
}
}

#[allow(clippy::from_over_into)] // the Into conversion is infallible, but From is not
impl Into<u64> for Thousandths {
fn into(self) -> u64 {
self.0 as u64
}
}

#[cfg(test)]
mod thousandths_tests {
use crate::time::Thousandths;

#[test]
fn test_new_valid() {
assert!(Thousandths::new(0).is_ok());
assert!(Thousandths::new(999).is_ok());
}

#[test]
fn test_new_invalid() {
assert!(Thousandths::new(1000).is_err());
assert!(Thousandths::new(1001).is_err());
}
}
1 change: 1 addition & 0 deletions crates/lox_core/src/time/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@

pub mod f64;
pub mod i64;
pub mod u64;
10 changes: 10 additions & 0 deletions crates/lox_core/src/time/constants/i64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,13 @@ pub const SECONDS_PER_MINUTE: i64 = 60;
pub const SECONDS_PER_HOUR: i64 = 60 * SECONDS_PER_MINUTE;

pub const SECONDS_PER_DAY: i64 = 24 * SECONDS_PER_HOUR;

pub const MILLISECONDS_PER_SECOND: i64 = 1_000;

pub const MICROSECONDS_PER_SECOND: i64 = 1_000_000;

pub const NANOSECONDS_PER_SECOND: i64 = 1_000_000_000;

pub const PICOSECONDS_PER_SECOND: i64 = 1_000_000_000_000;

pub const FEMTOSECONDS_PER_SECOND: i64 = 1_000_000_000_000_000;
29 changes: 29 additions & 0 deletions crates/lox_core/src/time/constants/u64.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2024. Helge Eichhorn and the LOX contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*/

pub const MILLISECONDS_PER_SECOND: u64 = 1_000;

pub const MICROSECONDS_PER_SECOND: u64 = 1_000_000;

pub const NANOSECONDS_PER_SECOND: u64 = 1_000_000_000;

pub const PICOSECONDS_PER_SECOND: u64 = 1_000_000_000_000;

pub const FEMTOSECONDS_PER_SECOND: u64 = 1_000_000_000_000_000;

pub const ATTOSECONDS_PER_SECOND: u64 = 1_000_000_000_000_000_000;

pub const ATTOSECONDS_PER_MILLISECOND: u64 = 1_000_000_000_000_000;

pub const ATTOSECONDS_PER_MICROSECOND: u64 = 1_000_000_000_000;

pub const ATTOSECONDS_PER_NANOSECOND: u64 = 1_000_000_000;

pub const ATTOSECONDS_PER_PICOSECOND: u64 = 1_000_000;

pub const ATTOSECONDS_PER_FEMTOSECOND: u64 = 1_000;
Loading
Loading