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

Added an implementation of From<Time> for Duration #131

Closed
wants to merge 9 commits into from
Closed
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ pub mod num {
#[cfg(not(feature = "std"))]
pub use num_traits::float::FloatCore as Float;

pub use num_traits::{pow, FromPrimitive, Num, One, Saturating, Signed, Zero};
pub use num_traits::{pow, AsPrimitive, FromPrimitive, Num, One, Saturating, Signed, Zero};

#[cfg(feature = "bigint-support")]
pub use num_bigint::{BigInt, BigUint};
Expand Down
43 changes: 43 additions & 0 deletions src/si/time.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! Time (base unit second, s<sup>1</sup>).

use ::lib::time::Duration;

quantity! {
/// Time (base unit second, s<sup>1</sup>).
quantity: Time; "time";
Expand Down Expand Up @@ -44,3 +46,44 @@ quantity! {
@year: 3.1536_E7; "a", "year", "years";
}
}

impl<U, V> From<Time<U, V>> for Duration
where
U: ::si::Units<V> + ?Sized,
V: ::num::Num + ::num::AsPrimitive<u64> + ::num::AsPrimitive<u32> + ::Conversion<V> + ::lib::cmp::PartialOrd,
second: ::Conversion<V, T = V::T>,
nanosecond: ::Conversion<V, T = V::T>,
{
fn from(mut t: Time<U, V>) -> Duration {
if t < Time::<U, V>::new::<second>(V::zero()) {
t = Time::<U, V>::new::<second>(V::zero()) - t
}
let secs = t.get::<second>().as_();
let nanos = (t % Time::<U, V>::new::<second>(V::one())).get::<nanosecond>().as_();
Duration::new(secs, nanos)
}
}

#[cfg(test)]
mod tests {
storage_types! {
types: Float;

use ::lib::time::Duration;
use si::quantities::*;
use si::time::second;

#[test]
fn from() {
let t = Time::new::<second>(-21.5);
let d: Duration = t.into();
assert_eq!(d.as_secs(), 21);
assert!(499_999_999 <= d.subsec_nanos() && d.subsec_nanos() <= 500_000_001);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason that we can't require this to be exactly 500,000,000?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Precision loss when I subtract t from zero is my current best guess. The way I implemented it originally, by casting the time to f64 and then converting that to a Duration did allow this to be 500,000,000 exactly. Perhaps it's only the f32 test that loses precision?


let t = Time::new::<second>(12.345);
let d: Duration = t.into();
assert_eq!(d.as_secs(), 12);
assert!(344_999_500 <= d.subsec_nanos() && d.subsec_nanos() <= 345_000_500);
}
}
}