1use crate::lib::time::Duration;
4use crate::num::{FromPrimitive, ToPrimitive, Zero};
5
6quantity! {
7 quantity: Time; "time";
9 dimension: ISQ<
11 Z0, Z0, P1, Z0, Z0, Z0, Z0>; units {
19 @yottasecond: prefix!(yotta); "Ys", "yottasecond", "yottaseconds";
20 @zettasecond: prefix!(zetta); "Zs", "zettasecond", "zettaseconds";
21 @exasecond: prefix!(exa); "Es", "exasecond", "exaseconds";
22 @petasecond: prefix!(peta); "Ps", "petasecond", "petaseconds";
23 @terasecond: prefix!(tera); "Ts", "terasecond", "teraseconds";
24 @gigasecond: prefix!(giga); "Gs", "gigasecond", "gigaseconds";
25 @megasecond: prefix!(mega); "Ms", "megasecond", "megaseconds";
26 @kilosecond: prefix!(kilo); "ks", "kilosecond", "kiloseconds";
27 @hectosecond: prefix!(hecto); "hs", "hectosecond", "hectoseconds";
28 @decasecond: prefix!(deca); "das", "decasecond", "decaseconds";
29 @second: prefix!(none); "s", "second", "seconds";
34 @decisecond: prefix!(deci); "ds", "decisecond", "deciseconds";
35 @centisecond: prefix!(centi); "cs", "centisecond", "centiseconds";
36 @millisecond: prefix!(milli); "ms", "millisecond", "milliseconds";
37 @microsecond: prefix!(micro); "µs", "microsecond", "microseconds";
38 @nanosecond: prefix!(nano); "ns", "nanosecond", "nanoseconds";
39 @picosecond: prefix!(pico); "ps", "picosecond", "picoseconds";
40 @femtosecond: prefix!(femto); "fs", "femtosecond", "femtoseconds";
41 @attosecond: prefix!(atto); "as", "attosecond", "attoseconds";
42 @zeptosecond: prefix!(zepto); "zs", "zeptosecond", "zeptoseconds";
43 @yoctosecond: prefix!(yocto); "ys", "yoctosecond", "yoctoseconds";
44
45 @second_sidereal: 9.972_696_E-1; "s (sidereal)", "second (sidereal)", "seconds (sidereal)";
46 @day: 8.64_E4; "d", "day", "days";
47 @day_sidereal: 8.616_409_E4; "d (sidereal)", "day (sidereal)", "days (sidereal)";
48 @hour: 3.6_E3; "h", "hour", "hours";
49 @hour_sidereal: 3.590_170_E3; "h (sidereal)", "hour (sidereal)", "hours (sidereal)";
50 @minute: 6.0_E1; "min", "minute", "minutes";
51 @shake: 1.0_E-8; "10.0 ns", "shake", "shakes";
52 @year: 3.1536_E7; "a", "year", "years";
53 @year_sidereal: 3.155_815_E7; "a (sidereal)", "year (sidereal)", "years (sidereal)";
54 @year_tropical: 3.155_693_E7; "a (tropical)", "year (tropical)", "years (tropical)";
55 }
56}
57
58#[derive(Debug, Clone, Copy)]
60pub enum TryFromError {
61 NegativeDuration,
65
66 Overflow,
68}
69
70impl<U, V> TryFrom<Time<U, V>> for Duration
80where
81 U: crate::si::Units<V> + ?Sized,
82 V: crate::num::Num + crate::Conversion<V> + PartialOrd + ToPrimitive,
83 second: crate::Conversion<V, T = V::T>,
84 nanosecond: crate::Conversion<V, T = V::T>,
85{
86 type Error = TryFromError;
87
88 fn try_from(time: Time<U, V>) -> Result<Self, Self::Error> {
89 if time < Time::<U, V>::zero() {
90 return Err(TryFromError::NegativeDuration);
91 }
92
93 let secs = time.get::<second>().to_u64();
94 let nanos = (time % Time::<U, V>::new::<second>(V::one())).get::<nanosecond>().to_u32();
95
96 match (secs, nanos) {
97 (Some(secs), Some(nanos)) => Ok(Self::new(secs, nanos)),
98 _ => Err(TryFromError::Overflow),
99 }
100 }
101}
102
103impl<U, V> TryFrom<Duration> for Time<U, V>
113where
114 U: crate::si::Units<V> + ?Sized,
115 V: crate::num::Num + crate::Conversion<V> + FromPrimitive,
116 second: crate::Conversion<V, T = V::T>,
117 nanosecond: crate::Conversion<V, T = V::T>,
118{
119 type Error = TryFromError;
120
121 fn try_from(duration: Duration) -> Result<Self, Self::Error> {
122 let secs = V::from_u64(duration.as_secs());
123 let nanos = V::from_u32(duration.subsec_nanos());
124
125 match (secs, nanos) {
126 (Some(secs), Some(nanos)) => {
127 Ok(Time::<U, V>::new::<second>(secs) + Time::<U, V>::new::<nanosecond>(nanos))
128 }
129 _ => Err(TryFromError::Overflow),
130 }
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 storage_types! {
137 types: PrimInt, BigInt, BigUint, Float;
138
139 use crate::ConversionFactor;
140 use crate::lib::convert::TryFrom;
141 use crate::lib::time::Duration;
142 use crate::num::{FromPrimitive, ToPrimitive, One, Zero};
143 use crate::si::quantities::*;
144 use crate::si::time::{TryFromError, second, nanosecond};
145 use crate::tests::*;
146 use quickcheck::TestResult;
147
148 quickcheck! {
149 fn duration_try_from(v: A<V>) -> bool {
150 let ns: V = <nanosecond as crate::Conversion<V>>::coefficient().value();
151 let t = Time::new::<second>((*v).clone());
152 let d = Duration::try_from(t);
153 let r = (*v).clone() % V::one();
154 let s = ((*v).clone() - r.clone()).to_u64();
155 let n = (r * (V::one() / &ns)).to_u32();
156
157 match (d, s, n) {
158 (Ok(d), Some(s), Some(n)) => d.as_secs() == s && d.subsec_nanos() == n,
159 (Err(TryFromError::NegativeDuration), _, _) if *v < V::zero() => true,
160 (Err(TryFromError::Overflow), None, _) => true,
161 (Err(TryFromError::Overflow), _, None) => true,
162 _ => false,
163 }
164 }
165
166 fn time_try_from(v: A<V>) -> TestResult {
167 if *v < V::zero() {
168 return TestResult::discard();
169 }
170
171 let ns: V = <nanosecond as crate::Conversion<V>>::coefficient().value();
172 let r = (*v).clone() % V::one();
173 let s = ((*v).clone() - r.clone()).to_u64();
174 let n = (r * (V::one() / &ns)).to_u32();
175
176 match (s, n) {
177 (Some(s), Some(n)) => TestResult::from_bool(
178 match (Time::try_from(Duration::new(s, n)), V::from_u64(s), V::from_u32(n)) {
179 (Ok(t), Some(s), Some(n)) => t == Time::new::<second>(s) + Time::new::<nanosecond>(n),
180 (Err(TryFromError::Overflow), None, _) => true,
181 (Err(TryFromError::Overflow), _, None) => true,
182 _ => false,
183 }),
184 _ => TestResult::discard(),
185 }
186 }
187 }
188 }
189}