1use crate::{Quantity, Unit};
26use qtty_derive::Unit;
27
28pub use crate::dimension::Time;
30
31pub trait TimeUnit: Unit<Dim = Time> {}
33impl<T: Unit<Dim = Time>> TimeUnit for T {}
34
35pub const SECONDS_PER_DAY: f64 = 86_400.0;
37
38#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
42#[unit(symbol = "as", dimension = Time, ratio = 1e-18)]
43pub struct Attosecond;
44pub type Attoseconds = Quantity<Attosecond>;
46pub const ATTOSEC: Attoseconds = Attoseconds::new(1.0);
48
49#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
51#[unit(symbol = "fs", dimension = Time, ratio = 1e-15)]
52pub struct Femtosecond;
53pub type Femtoseconds = Quantity<Femtosecond>;
55pub const FEMTOSEC: Femtoseconds = Femtoseconds::new(1.0);
57
58#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
60#[unit(symbol = "ps", dimension = Time, ratio = 1e-12)]
61pub struct Picosecond;
62pub type Picoseconds = Quantity<Picosecond>;
64pub const PICOSEC: Picoseconds = Picoseconds::new(1.0);
66
67#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
69#[unit(symbol = "ns", dimension = Time, ratio = 1e-9)]
70pub struct Nanosecond;
71pub type Nanoseconds = Quantity<Nanosecond>;
73pub const NANOSEC: Nanoseconds = Nanoseconds::new(1.0);
75
76#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
78#[unit(symbol = "µs", dimension = Time, ratio = 1e-6)]
79pub struct Microsecond;
80pub type Microseconds = Quantity<Microsecond>;
82pub const MICROSEC: Microseconds = Microseconds::new(1.0);
84
85#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
87#[unit(symbol = "ms", dimension = Time, ratio = 1e-3)]
88pub struct Millisecond;
89pub type Milliseconds = Quantity<Millisecond>;
91pub const MILLISEC: Milliseconds = Milliseconds::new(1.0);
93
94#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
96#[unit(symbol = "cs", dimension = Time, ratio = 1e-2)]
97pub struct Centisecond;
98pub type Centiseconds = Quantity<Centisecond>;
100pub const CENTISEC: Centiseconds = Centiseconds::new(1.0);
102
103#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
105#[unit(symbol = "ds", dimension = Time, ratio = 1e-1)]
106pub struct Decisecond;
107pub type Deciseconds = Quantity<Decisecond>;
109pub const DECISEC: Deciseconds = Deciseconds::new(1.0);
111
112#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
114#[unit(symbol = "s", dimension = Time, ratio = 1.0)]
115pub struct Second;
116pub type Seconds = Quantity<Second>;
118pub const SEC: Seconds = Seconds::new(1.0);
120
121#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
125#[unit(symbol = "das", dimension = Time, ratio = 10.0)]
126pub struct Decasecond;
127pub type Decaseconds = Quantity<Decasecond>;
129pub const DECASEC: Decaseconds = Decaseconds::new(1.0);
131
132#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
134#[unit(symbol = "hs", dimension = Time, ratio = 100.0)]
135pub struct Hectosecond;
136pub type Hectoseconds = Quantity<Hectosecond>;
138pub const HECTOSEC: Hectoseconds = Hectoseconds::new(1.0);
140
141#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
143#[unit(symbol = "ks", dimension = Time, ratio = 1_000.0)]
144pub struct Kilosecond;
145pub type Kiloseconds = Quantity<Kilosecond>;
147pub const KILOSEC: Kiloseconds = Kiloseconds::new(1.0);
149
150#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
152#[unit(symbol = "Ms", dimension = Time, ratio = 1e6)]
153pub struct Megasecond;
154pub type Megaseconds = Quantity<Megasecond>;
156pub const MEGASEC: Megaseconds = Megaseconds::new(1.0);
158
159#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
161#[unit(symbol = "Gs", dimension = Time, ratio = 1e9)]
162pub struct Gigasecond;
163pub type Gigaseconds = Quantity<Gigasecond>;
165pub const GIGASEC: Gigaseconds = Gigaseconds::new(1.0);
167
168#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
170#[unit(symbol = "Ts", dimension = Time, ratio = 1e12)]
171pub struct Terasecond;
172pub type Teraseconds = Quantity<Terasecond>;
174pub const TERASEC: Teraseconds = Teraseconds::new(1.0);
176
177#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
181#[unit(symbol = "min", dimension = Time, ratio = 60.0)]
182pub struct Minute;
183pub type Minutes = Quantity<Minute>;
185pub const MIN: Minutes = Minutes::new(1.0);
187
188#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
190#[unit(symbol = "h", dimension = Time, ratio = 3_600.0)]
191pub struct Hour;
192pub type Hours = Quantity<Hour>;
194pub const HOUR: Hours = Hours::new(1.0);
196
197#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
199#[unit(symbol = "d", dimension = Time, ratio = SECONDS_PER_DAY)]
200pub struct Day;
201pub type Days = Quantity<Day>;
203pub const DAY: Days = Days::new(1.0);
205
206#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
208#[unit(symbol = "wk", dimension = Time, ratio = 7.0 * SECONDS_PER_DAY)]
209pub struct Week;
210pub type Weeks = Quantity<Week>;
212pub const WEEK: Weeks = Weeks::new(1.0);
214
215#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
217#[unit(symbol = "fn", dimension = Time, ratio = 14.0 * SECONDS_PER_DAY)]
218pub struct Fortnight;
219pub type Fortnights = Quantity<Fortnight>;
221pub const FORTNIGHT: Fortnights = Fortnights::new(1.0);
223
224#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
228#[unit(symbol = "yr", dimension = Time, ratio = 365.242_5 * SECONDS_PER_DAY)]
229pub struct Year;
230pub type Years = Quantity<Year>;
232pub const YEAR: Years = Years::new(1.0);
234
235#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
237#[unit(symbol = "dec", dimension = Time, ratio = 10.0 * 365.242_5 * SECONDS_PER_DAY)]
238pub struct Decade;
239pub type Decades = Quantity<Decade>;
241pub const DECADE: Decades = Decades::new(1.0);
243
244#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
246#[unit(symbol = "cent", dimension = Time, ratio = 100.0 * 365.242_5 * SECONDS_PER_DAY)]
247pub struct Century;
248pub type Centuries = Quantity<Century>;
250pub const CENTURY: Centuries = Centuries::new(1.0);
252
253#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
255#[unit(symbol = "mill", dimension = Time, ratio = 1000.0 * 365.242_5 * SECONDS_PER_DAY)]
256pub struct Millennium;
257pub type Millennia = Quantity<Millennium>;
259pub const MILLENNIUM: Millennia = Millennia::new(1.0);
261
262#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
266#[unit(symbol = "a", dimension = Time, ratio = 365.25 * SECONDS_PER_DAY)]
267pub struct JulianYear;
268pub type JulianYears = Quantity<JulianYear>;
270pub const JULIAN_YEAR: JulianYears = JulianYears::new(1.0);
272
273#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
275#[unit(symbol = "JC", dimension = Time, ratio = 36_525.0 * SECONDS_PER_DAY)]
276pub struct JulianCentury;
277pub type JulianCenturies = Quantity<JulianCentury>;
279pub const JULIAN_CENTURY: JulianCenturies = JulianCenturies::new(1.0);
281
282#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
288#[unit(symbol = "sd", dimension = Time, ratio = 86_164.090_5)]
289pub struct SiderealDay;
290pub type SiderealDays = Quantity<SiderealDay>;
292pub const SIDEREAL_DAY: SiderealDays = SiderealDays::new(1.0);
294
295#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
299#[unit(symbol = "synmo", dimension = Time, ratio = 29.530_588 * SECONDS_PER_DAY)]
300pub struct SynodicMonth;
301pub type SynodicMonths = Quantity<SynodicMonth>;
303pub const SYNODIC_MONTH: SynodicMonths = SynodicMonths::new(1.0);
305
306#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
310#[unit(symbol = "syr", dimension = Time, ratio = 365.256_363_004 * SECONDS_PER_DAY)]
311pub struct SiderealYear;
312pub type SiderealYears = Quantity<SiderealYear>;
314pub const SIDEREAL_YEAR: SiderealYears = SiderealYears::new(1.0);
316
317#[cfg(test)]
318mod tests {
319 use super::*;
320 use approx::assert_abs_diff_eq;
321 use proptest::prelude::*;
322
323 #[test]
328 fn seconds_to_minutes() {
329 let sec = Seconds::new(60.0);
330 let min = sec.to::<Minute>();
331 assert_abs_diff_eq!(min.value(), 1.0, epsilon = 1e-12);
332 }
333
334 #[test]
335 fn minutes_to_hours() {
336 let min = Minutes::new(60.0);
337 let hr = min.to::<Hour>();
338 assert_abs_diff_eq!(hr.value(), 1.0, epsilon = 1e-12);
339 }
340
341 #[test]
342 fn hours_to_days() {
343 let hr = Hours::new(24.0);
344 let day = hr.to::<Day>();
345 assert_abs_diff_eq!(day.value(), 1.0, epsilon = 1e-12);
346 }
347
348 #[test]
349 fn seconds_86400_equals_one_day() {
350 let sec = Seconds::new(86400.0);
351 let day = sec.to::<Day>();
352 assert_abs_diff_eq!(day.value(), 1.0, epsilon = 1e-12);
353 }
354
355 #[test]
356 fn day_to_seconds() {
357 let day = Days::new(1.0);
358 let sec = day.to::<Second>();
359 assert_abs_diff_eq!(sec.value(), 86400.0, epsilon = 1e-9);
360 }
361
362 #[test]
363 fn days_to_weeks() {
364 let day = Days::new(7.0);
365 let week = day.to::<Week>();
366 assert_abs_diff_eq!(week.value(), 1.0, epsilon = 1e-12);
367 }
368
369 #[test]
370 fn julian_year_to_days() {
371 let jy = JulianYears::new(1.0);
372 let day = jy.to::<Day>();
373 assert_abs_diff_eq!(day.value(), 365.25, epsilon = 1e-9);
374 }
375
376 #[test]
377 fn julian_century_to_days() {
378 let jc = JulianCenturies::new(1.0);
379 let day = jc.to::<Day>();
380 assert_abs_diff_eq!(day.value(), 36525.0, epsilon = 1e-9);
381 }
382
383 #[test]
384 fn julian_century_to_julian_years() {
385 let jc = JulianCenturies::new(1.0);
386 let jy = jc.to::<JulianYear>();
387 assert_abs_diff_eq!(jy.value(), 100.0, epsilon = 1e-9);
388 }
389
390 #[test]
391 fn tropical_year_to_days() {
392 let y = Years::new(1.0);
393 let day = y.to::<Day>();
394 assert_abs_diff_eq!(day.value(), 365.2425, epsilon = 1e-9);
395 }
396
397 #[test]
398 fn century_to_days() {
399 let c = Centuries::new(1.0);
400 let day = c.to::<Day>();
401 assert_abs_diff_eq!(day.value(), 36524.25, epsilon = 1e-9);
402 }
403
404 #[test]
405 fn milliseconds_to_seconds() {
406 let ms = Milliseconds::new(1000.0);
407 let sec = ms.to::<Second>();
408 assert_abs_diff_eq!(sec.value(), 1.0, epsilon = 1e-9);
409 }
410
411 #[test]
416 fn roundtrip_day_second() {
417 let original = Days::new(1.5);
418 let converted = original.to::<Second>();
419 let back = converted.to::<Day>();
420 assert_abs_diff_eq!(back.value(), original.value(), epsilon = 1e-12);
421 }
422
423 #[test]
424 fn roundtrip_julian_year_day() {
425 let original = JulianYears::new(2.5);
426 let converted = original.to::<Day>();
427 let back = converted.to::<JulianYear>();
428 assert_abs_diff_eq!(back.value(), original.value(), epsilon = 1e-12);
429 }
430
431 #[test]
436 fn second_ratio_sanity() {
437 assert_abs_diff_eq!(Second::RATIO, 1.0, epsilon = 1e-15);
439 }
440
441 #[test]
442 fn minute_ratio_sanity() {
443 assert_abs_diff_eq!(Minute::RATIO, 60.0, epsilon = 1e-15);
445 }
446
447 #[test]
448 fn hour_ratio_sanity() {
449 assert_abs_diff_eq!(Hour::RATIO, 3_600.0, epsilon = 1e-15);
451 }
452
453 proptest! {
458 #[test]
459 fn prop_roundtrip_day_second(d in -1e6..1e6f64) {
460 let original = Days::new(d);
461 let converted = original.to::<Second>();
462 let back = converted.to::<Day>();
463 prop_assert!((back.value() - original.value()).abs() < 1e-9);
464 }
465
466 #[test]
467 fn prop_day_second_ratio(d in 1e-6..1e6f64) {
468 let day = Days::new(d);
469 let sec = day.to::<Second>();
470 prop_assert!((sec.value() / day.value() - 86400.0).abs() < 1e-9);
472 }
473
474 #[test]
475 fn prop_julian_year_day_ratio(y in 1e-6..1e6f64) {
476 let jy = JulianYears::new(y);
477 let day = jy.to::<Day>();
478 prop_assert!((day.value() / jy.value() - 365.25).abs() < 1e-9);
480 }
481 }
482}