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> crate::lib::convert::TryFrom<Time<U, V>> for Duration
82where
83 U: crate::si::Units<V> + ?Sized,
84 V: crate::num::Num + crate::Conversion<V> + PartialOrd + ToPrimitive,
85 second: crate::Conversion<V, T = V::T>,
86 nanosecond: crate::Conversion<V, T = V::T>,
87{
88 type Error = TryFromError;
89
90 fn try_from(time: Time<U, V>) -> Result<Self, Self::Error> {
91 if time < Time::<U, V>::zero() {
92 return Err(TryFromError::NegativeDuration);
93 }
94
95 let secs = time.get::<second>().to_u64();
96 let nanos = (time % Time::<U, V>::new::<second>(V::one())).get::<nanosecond>().to_u32();
97
98 match (secs, nanos) {
99 (Some(secs), Some(nanos)) => Ok(Self::new(secs, nanos)),
100 _ => Err(TryFromError::Overflow),
101 }
102 }
103}
104
105impl<U, V> crate::lib::convert::TryFrom<Duration> for Time<U, V>
117where
118 U: crate::si::Units<V> + ?Sized,
119 V: crate::num::Num + crate::Conversion<V> + FromPrimitive,
120 second: crate::Conversion<V, T = V::T>,
121 nanosecond: crate::Conversion<V, T = V::T>,
122{
123 type Error = TryFromError;
124
125 fn try_from(duration: Duration) -> Result<Self, Self::Error> {
126 let secs = V::from_u64(duration.as_secs());
127 let nanos = V::from_u32(duration.subsec_nanos());
128
129 match (secs, nanos) {
130 (Some(secs), Some(nanos)) => {
131 Ok(Time::<U, V>::new::<second>(secs) + Time::<U, V>::new::<nanosecond>(nanos))
132 }
133 _ => Err(TryFromError::Overflow),
134 }
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 storage_types! {
141 types: PrimInt, BigInt, BigUint, Float;
142
143 use crate::ConversionFactor;
144 use crate::lib::convert::TryFrom;
145 use crate::lib::time::Duration;
146 use crate::num::{FromPrimitive, ToPrimitive, One, Zero};
147 use crate::si::quantities::*;
148 use crate::si::time::{TryFromError, second, nanosecond};
149 use crate::tests::*;
150 use quickcheck::TestResult;
151
152 quickcheck! {
153 fn duration_try_from(v: A<V>) -> bool {
154 let ns: V = <nanosecond as crate::Conversion<V>>::coefficient().value();
155 let t = Time::new::<second>((*v).clone());
156 let d = Duration::try_from(t);
157 let r = (*v).clone() % V::one();
158 let s = ((*v).clone() - r.clone()).to_u64();
159 let n = (r * (V::one() / &ns)).to_u32();
160
161 match (d, s, n) {
162 (Ok(d), Some(s), Some(n)) => d.as_secs() == s && d.subsec_nanos() == n,
163 (Err(TryFromError::NegativeDuration), _, _) if *v < V::zero() => true,
164 (Err(TryFromError::Overflow), None, _) => true,
165 (Err(TryFromError::Overflow), _, None) => true,
166 _ => false,
167 }
168 }
169
170 fn time_try_from(v: A<V>) -> TestResult {
171 if *v < V::zero() {
172 return TestResult::discard();
173 }
174
175 let ns: V = <nanosecond as crate::Conversion<V>>::coefficient().value();
176 let r = (*v).clone() % V::one();
177 let s = ((*v).clone() - r.clone()).to_u64();
178 let n = (r * (V::one() / &ns)).to_u32();
179
180 return match (s, n) {
181 (Some(s), Some(n)) => TestResult::from_bool(
182 match (Time::try_from(Duration::new(s, n)), V::from_u64(s), V::from_u32(n)) {
183 (Ok(t), Some(s), Some(n)) => t == Time::new::<second>(s) + Time::new::<nanosecond>(n),
184 (Err(TryFromError::Overflow), None, _) => true,
185 (Err(TryFromError::Overflow), _, None) => true,
186 _ => false,
187 }),
188 _ => TestResult::discard(),
189 }
190 }
191 }
192 }
193}