Skip to content

Commit

Permalink
Merge pull request #299 from nyx-space/217-duration-and-epoch-serde-t…
Browse files Browse the repository at this point in the history
…o-be-human-readable

Duration serde now human readable + Display of Epoch is now Gregorian in its initialization time scale
  • Loading branch information
ChristopherRabotin authored Apr 26, 2024
2 parents a9d214f + 8ef8a78 commit f9d4100
Show file tree
Hide file tree
Showing 10 changed files with 93 additions and 92 deletions.
47 changes: 40 additions & 7 deletions src/duration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ use core::fmt;
use core::hash::{Hash, Hasher};

#[cfg(feature = "serde")]
use serde_derive::{Deserialize, Serialize};
use serde::{Deserialize, Deserializer, Serialize, Serializer};

#[cfg(feature = "serde")]
use core::str::FromStr;

#[cfg(not(kani))]
pub mod parse;
Expand Down Expand Up @@ -63,7 +66,6 @@ pub mod ops;
#[repr(C)]
#[cfg_attr(feature = "python", pyclass)]
#[cfg_attr(feature = "python", pyo3(module = "hifitime"))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Duration {
pub(crate) centuries: i16,
pub(crate) nanoseconds: u64,
Expand Down Expand Up @@ -103,6 +105,30 @@ impl Default for Duration {
}
}

#[cfg(not(kani))]
#[cfg(feature = "serde")]
impl Serialize for Duration {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let s = self.to_string();
serializer.serialize_str(&s)
}
}

#[cfg(not(kani))]
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for Duration {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Duration::from_str(&s).map_err(serde::de::Error::custom)
}
}

// Defines the methods that should be classmethods in Python, but must be redefined as per https://github.com/PyO3/pyo3/issues/1003#issuecomment-844433346
impl Duration {
/// A duration of exactly zero nanoseconds
Expand Down Expand Up @@ -730,11 +756,18 @@ mod ut_duration {
#[test]
#[cfg(feature = "serde")]
fn test_serdes() {
let dt = Duration::from_seconds(10.1);
let content = r#"{"centuries":0,"nanoseconds":10100000000}"#;
assert_eq!(content, serde_json::to_string(&dt).unwrap());
let parsed: Duration = serde_json::from_str(content).unwrap();
assert_eq!(dt, parsed);
for (dt, content) in [
(Duration::from_seconds(10.1), r#""10 s 100 ms""#),
(1.0_f64.days() + 99.nanoseconds(), r#""1 days 99 ns""#),
(
1.0_f64.centuries() + 99.seconds(),
r#""36525 days 1 min 39 s""#,
),
] {
assert_eq!(content, serde_json::to_string(&dt).unwrap());
let parsed: Duration = serde_json::from_str(content).unwrap();
assert_eq!(dt, parsed);
}
}

#[test]
Expand Down
4 changes: 2 additions & 2 deletions src/epoch/formatting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use core::fmt;

use crate::{Epoch, TimeScale};

impl fmt::Debug for Epoch {
impl fmt::Display for Epoch {
/// Print this epoch in Gregorian in the time scale used at initialization
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let (y, mm, dd, hh, min, s, nanos) =
Expand All @@ -33,7 +33,7 @@ impl fmt::Debug for Epoch {
}
}

impl fmt::Display for Epoch {
impl fmt::Debug for Epoch {
/// The default format of an epoch is in UTC
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let ts = TimeScale::UTC;
Expand Down
15 changes: 10 additions & 5 deletions src/epoch/gregorian.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,21 +175,26 @@ impl Epoch {
/// ```
/// use hifitime::Epoch;
///
/// let dt = Epoch::from_tai_parts(1, 537582752000000000);
/// let dt_tai = Epoch::from_tai_parts(1, 537582752000000000);
///
/// // With the std feature, you may use FromStr as such
/// // let dt_str = "2017-01-14T00:31:55 UTC";
/// // let dt = Epoch::from_gregorian_str(dt_str).unwrap()
/// let dt_str = "2017-01-14T00:31:55 UTC";
/// let dt = Epoch::from_gregorian_str(dt_str).unwrap();
///
/// let (y, m, d, h, min, s, _) = dt.to_gregorian_utc();
/// let (y, m, d, h, min, s, _) = dt_tai.to_gregorian_utc();
/// assert_eq!(y, 2017);
/// assert_eq!(m, 1);
/// assert_eq!(d, 14);
/// assert_eq!(h, 0);
/// assert_eq!(min, 31);
/// assert_eq!(s, 55);
/// #[cfg(feature = "std")]
/// {
/// assert_eq!("2017-01-14T00:31:55 UTC", format!("{dt_tai:?}"));
/// // dt_tai is initialized from TAI, so the default print is the Gregorian in that time system
/// assert_eq!("2017-01-14T00:32:32 TAI", format!("{dt_tai}"));
/// // But dt is initialized from UTC, so the default print and the debug print are both in UTC.
/// assert_eq!("2017-01-14T00:31:55 UTC", format!("{dt}"));
/// }
/// ```
pub fn to_gregorian_utc(&self) -> (i32, u8, u8, u8, u8, u8, u32) {
let ts = TimeScale::UTC;
Expand Down
File renamed without changes.
File renamed without changes.
47 changes: 24 additions & 23 deletions src/epoch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,24 @@
* Documentation: https://nyxspace.com/
*/

mod formatting;
mod gregorian;
mod ops;
mod with_funcs;

#[cfg(feature = "std")]
mod leap_seconds_file;
#[cfg(feature = "std")]
mod system_time;

#[cfg(kani)]
mod kani_verif;

#[cfg(feature = "ut1")]
pub mod ut1;

pub mod leap_seconds;

use crate::duration::{Duration, Unit};
use crate::efmt::format::Format;
use crate::leap_seconds::{LatestLeapSeconds, LeapSecondProvider};
Expand All @@ -17,11 +35,15 @@ use crate::{
GST_REF_EPOCH, J1900_OFFSET, J2000_TO_J1900_DURATION, MJD_OFFSET, NANOSECONDS_PER_DAY,
QZSST_REF_EPOCH, UNIX_REF_EPOCH,
};
use core::cmp::Eq;
use core::str::FromStr;
pub use gregorian::is_gregorian_valid;

#[cfg(not(kani))]
use crate::ParsingErrors;

use core::cmp::Eq;
#[cfg(kani)]
use kani::assert;

#[cfg(feature = "python")]
mod python;
Expand All @@ -33,31 +55,10 @@ use pyo3::prelude::*;
#[cfg(feature = "serde")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};

use core::str::FromStr;

#[cfg(feature = "ut1")]
pub mod ut1;

#[cfg(not(feature = "std"))]
#[allow(unused_imports)] // Import is indeed used.
use num_traits::Float;

#[cfg(feature = "std")]
mod system_time;

#[cfg(kani)]
mod kani_verif;

#[cfg(kani)]
use kani::assert;

mod gregorian;
pub use gregorian::is_gregorian_valid;

mod formatting;
mod ops;
mod with_funcs;

pub(crate) const TT_OFFSET_MS: i64 = 32_184;
pub(crate) const ET_OFFSET_US: i64 = 32_184_935;

Expand Down Expand Up @@ -1402,7 +1403,7 @@ mod ut_epoch {
#[test]
#[cfg(feature = "serde")]
fn test_serdes() {
let e = Epoch::from_gregorian_utc(2020, 01, 01, 0, 0, 0, 0);
let e = Epoch::from_gregorian_utc_at_midnight(2020, 01, 01);
let content = r#""2020-01-01T00:00:00 UTC""#;
assert_eq!(content, serde_json::to_string(&e).unwrap());
let parsed: Epoch = serde_json::from_str(content).unwrap();
Expand Down
2 changes: 1 addition & 1 deletion src/epoch/python.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::{prelude::Format, Duration, Epoch, Errors, TimeScale};

use core::str::FromStr;

use crate::leap_seconds_file::LeapSecondsFile;
use crate::epoch::leap_seconds_file::LeapSecondsFile;
use pyo3::prelude::*;
use pyo3::pyclass::CompareOp;
use pyo3::types::PyType;
Expand Down
6 changes: 0 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ pub mod errors;
pub use errors::{Errors, ParsingErrors};

mod epoch;

pub use epoch::*;

mod duration;
Expand All @@ -90,11 +89,6 @@ pub use weekday::*;
mod month;
pub use month::*;

pub mod leap_seconds;

#[cfg(feature = "std")]
mod leap_seconds_file;

pub mod prelude {
pub use crate::efmt::{Format, Formatter};
pub use crate::{
Expand Down
6 changes: 3 additions & 3 deletions src/timescale/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,15 +249,15 @@ mod unit_test_timescale {
use crate::{Duration, Epoch, Unit};
let prime_e = Epoch::from_duration(Duration::ZERO, TimeScale::TAI);
assert_eq!(prime_e.duration, Duration::ZERO);
assert_eq!(format!("{prime_e:?}"), "1900-01-01T00:00:00 TAI");
assert_eq!(format!("{prime_e}"), "1900-01-01T00:00:00 TAI");
// NOTE: There are only 36524 days in the 20th century, but one century is 36425, so we "overflow" the next century by one day!
assert_eq!(
format!("{:?}", prime_e + Unit::Century * 1),
format!("{}", prime_e + Unit::Century * 1),
"2000-01-02T00:00:00 TAI"
);

assert_eq!(
format!("{:?}", TimeScale::ET.reference_epoch()),
format!("{}", TimeScale::ET.reference_epoch()),
"2000-01-01T12:00:00 ET"
);
}
Expand Down
Loading

0 comments on commit f9d4100

Please sign in to comment.