1use crate::{Dimension, Quantity, Unit};
26use qtty_derive::Unit;
27
28pub enum Time {}
30impl Dimension for Time {}
31
32pub trait TimeUnit: Unit<Dim = Time> {}
34impl<T: Unit<Dim = Time>> TimeUnit for T {}
35
36pub const SECONDS_PER_DAY: f64 = 86_400.0;
38
39#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
43#[unit(symbol = "as", dimension = Time, ratio = 1e-18)]
44pub struct Attosecond;
45pub type Attoseconds = Quantity<Attosecond>;
47pub const ATTOSEC: Attoseconds = Attoseconds::new(1.0);
49
50#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
52#[unit(symbol = "fs", dimension = Time, ratio = 1e-15)]
53pub struct Femtosecond;
54pub type Femtoseconds = Quantity<Femtosecond>;
56pub const FEMTOSEC: Femtoseconds = Femtoseconds::new(1.0);
58
59#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
61#[unit(symbol = "ps", dimension = Time, ratio = 1e-12)]
62pub struct Picosecond;
63pub type Picoseconds = Quantity<Picosecond>;
65pub const PICOSEC: Picoseconds = Picoseconds::new(1.0);
67
68#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
70#[unit(symbol = "ns", dimension = Time, ratio = 1e-9)]
71pub struct Nanosecond;
72pub type Nanoseconds = Quantity<Nanosecond>;
74pub const NANOSEC: Nanoseconds = Nanoseconds::new(1.0);
76
77#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
79#[unit(symbol = "µs", dimension = Time, ratio = 1e-6)]
80pub struct Microsecond;
81pub type Microseconds = Quantity<Microsecond>;
83pub const MICROSEC: Microseconds = Microseconds::new(1.0);
85
86#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
88#[unit(symbol = "ms", dimension = Time, ratio = 1e-3)]
89pub struct Millisecond;
90pub type Milliseconds = Quantity<Millisecond>;
92pub const MILLISEC: Milliseconds = Milliseconds::new(1.0);
94
95#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
97#[unit(symbol = "cs", dimension = Time, ratio = 1e-2)]
98pub struct Centisecond;
99pub type Centiseconds = Quantity<Centisecond>;
101pub const CENTISEC: Centiseconds = Centiseconds::new(1.0);
103
104#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
106#[unit(symbol = "ds", dimension = Time, ratio = 1e-1)]
107pub struct Decisecond;
108pub type Deciseconds = Quantity<Decisecond>;
110pub const DECISEC: Deciseconds = Deciseconds::new(1.0);
112
113#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
115#[unit(symbol = "s", dimension = Time, ratio = 1.0)]
116pub struct Second;
117pub type Seconds = Quantity<Second>;
119pub const SEC: Seconds = Seconds::new(1.0);
121
122#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
126#[unit(symbol = "das", dimension = Time, ratio = 10.0)]
127pub struct Decasecond;
128pub type Decaseconds = Quantity<Decasecond>;
130pub const DECASEC: Decaseconds = Decaseconds::new(1.0);
132
133#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
135#[unit(symbol = "hs", dimension = Time, ratio = 100.0)]
136pub struct Hectosecond;
137pub type Hectoseconds = Quantity<Hectosecond>;
139pub const HECTOSEC: Hectoseconds = Hectoseconds::new(1.0);
141
142#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
144#[unit(symbol = "ks", dimension = Time, ratio = 1_000.0)]
145pub struct Kilosecond;
146pub type Kiloseconds = Quantity<Kilosecond>;
148pub const KILOSEC: Kiloseconds = Kiloseconds::new(1.0);
150
151#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
153#[unit(symbol = "Ms", dimension = Time, ratio = 1e6)]
154pub struct Megasecond;
155pub type Megaseconds = Quantity<Megasecond>;
157pub const MEGASEC: Megaseconds = Megaseconds::new(1.0);
159
160#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
162#[unit(symbol = "Gs", dimension = Time, ratio = 1e9)]
163pub struct Gigasecond;
164pub type Gigaseconds = Quantity<Gigasecond>;
166pub const GIGASEC: Gigaseconds = Gigaseconds::new(1.0);
168
169#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
171#[unit(symbol = "Ts", dimension = Time, ratio = 1e12)]
172pub struct Terasecond;
173pub type Teraseconds = Quantity<Terasecond>;
175pub const TERASEC: Teraseconds = Teraseconds::new(1.0);
177
178#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
182#[unit(symbol = "min", dimension = Time, ratio = 60.0)]
183pub struct Minute;
184pub type Minutes = Quantity<Minute>;
186pub const MIN: Minutes = Minutes::new(1.0);
188
189#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
191#[unit(symbol = "h", dimension = Time, ratio = 3_600.0)]
192pub struct Hour;
193pub type Hours = Quantity<Hour>;
195pub const HOUR: Hours = Hours::new(1.0);
197
198#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
200#[unit(symbol = "d", dimension = Time, ratio = SECONDS_PER_DAY)]
201pub struct Day;
202pub type Days = Quantity<Day>;
204pub const DAY: Days = Days::new(1.0);
206
207#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
209#[unit(symbol = "wk", dimension = Time, ratio = 7.0 * SECONDS_PER_DAY)]
210pub struct Week;
211pub type Weeks = Quantity<Week>;
213pub const WEEK: Weeks = Weeks::new(1.0);
215
216#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
218#[unit(symbol = "fn", dimension = Time, ratio = 14.0 * SECONDS_PER_DAY)]
219pub struct Fortnight;
220pub type Fortnights = Quantity<Fortnight>;
222pub const FORTNIGHT: Fortnights = Fortnights::new(1.0);
224
225#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
229#[unit(symbol = "yr", dimension = Time, ratio = 365.242_5 * SECONDS_PER_DAY)]
230pub struct Year;
231pub type Years = Quantity<Year>;
233pub const YEAR: Years = Years::new(1.0);
235
236#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
238#[unit(symbol = "dec", dimension = Time, ratio = 10.0 * 365.242_5 * SECONDS_PER_DAY)]
239pub struct Decade;
240pub type Decades = Quantity<Decade>;
242pub const DECADE: Decades = Decades::new(1.0);
244
245#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
247#[unit(symbol = "cent", dimension = Time, ratio = 100.0 * 365.242_5 * SECONDS_PER_DAY)]
248pub struct Century;
249pub type Centuries = Quantity<Century>;
251pub const CENTURY: Centuries = Centuries::new(1.0);
253
254#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
256#[unit(symbol = "mill", dimension = Time, ratio = 1000.0 * 365.242_5 * SECONDS_PER_DAY)]
257pub struct Millennium;
258pub type Millennia = Quantity<Millennium>;
260pub const MILLENNIUM: Millennia = Millennia::new(1.0);
262
263#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
267#[unit(symbol = "a", dimension = Time, ratio = 365.25 * SECONDS_PER_DAY)]
268pub struct JulianYear;
269pub type JulianYears = Quantity<JulianYear>;
271pub const JULIAN_YEAR: JulianYears = JulianYears::new(1.0);
273
274#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
276#[unit(symbol = "JC", dimension = Time, ratio = 36_525.0 * SECONDS_PER_DAY)]
277pub struct JulianCentury;
278pub type JulianCenturies = Quantity<JulianCentury>;
280pub const JULIAN_CENTURY: JulianCenturies = JulianCenturies::new(1.0);
282
283#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
289#[unit(symbol = "sd", dimension = Time, ratio = 86_164.090_5)]
290pub struct SiderealDay;
291pub type SiderealDays = Quantity<SiderealDay>;
293pub const SIDEREAL_DAY: SiderealDays = SiderealDays::new(1.0);
295
296#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
300#[unit(symbol = "synmo", dimension = Time, ratio = 29.530_588 * SECONDS_PER_DAY)]
301pub struct SynodicMonth;
302pub type SynodicMonths = Quantity<SynodicMonth>;
304pub const SYNODIC_MONTH: SynodicMonths = SynodicMonths::new(1.0);
306
307#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
311#[unit(symbol = "syr", dimension = Time, ratio = 365.256_363_004 * SECONDS_PER_DAY)]
312pub struct SiderealYear;
313pub type SiderealYears = Quantity<SiderealYear>;
315pub const SIDEREAL_YEAR: SiderealYears = SiderealYears::new(1.0);
317
318#[cfg(test)]
319mod tests {
320 use super::*;
321 use approx::assert_abs_diff_eq;
322 use proptest::prelude::*;
323
324 #[test]
329 fn seconds_to_minutes() {
330 let sec = Seconds::new(60.0);
331 let min = sec.to::<Minute>();
332 assert_abs_diff_eq!(min.value(), 1.0, epsilon = 1e-12);
333 }
334
335 #[test]
336 fn minutes_to_hours() {
337 let min = Minutes::new(60.0);
338 let hr = min.to::<Hour>();
339 assert_abs_diff_eq!(hr.value(), 1.0, epsilon = 1e-12);
340 }
341
342 #[test]
343 fn hours_to_days() {
344 let hr = Hours::new(24.0);
345 let day = hr.to::<Day>();
346 assert_abs_diff_eq!(day.value(), 1.0, epsilon = 1e-12);
347 }
348
349 #[test]
350 fn seconds_86400_equals_one_day() {
351 let sec = Seconds::new(86400.0);
352 let day = sec.to::<Day>();
353 assert_abs_diff_eq!(day.value(), 1.0, epsilon = 1e-12);
354 }
355
356 #[test]
357 fn day_to_seconds() {
358 let day = Days::new(1.0);
359 let sec = day.to::<Second>();
360 assert_abs_diff_eq!(sec.value(), 86400.0, epsilon = 1e-9);
361 }
362
363 #[test]
364 fn days_to_weeks() {
365 let day = Days::new(7.0);
366 let week = day.to::<Week>();
367 assert_abs_diff_eq!(week.value(), 1.0, epsilon = 1e-12);
368 }
369
370 #[test]
371 fn julian_year_to_days() {
372 let jy = JulianYears::new(1.0);
373 let day = jy.to::<Day>();
374 assert_abs_diff_eq!(day.value(), 365.25, epsilon = 1e-9);
375 }
376
377 #[test]
378 fn julian_century_to_days() {
379 let jc = JulianCenturies::new(1.0);
380 let day = jc.to::<Day>();
381 assert_abs_diff_eq!(day.value(), 36525.0, epsilon = 1e-9);
382 }
383
384 #[test]
385 fn julian_century_to_julian_years() {
386 let jc = JulianCenturies::new(1.0);
387 let jy = jc.to::<JulianYear>();
388 assert_abs_diff_eq!(jy.value(), 100.0, epsilon = 1e-9);
389 }
390
391 #[test]
392 fn tropical_year_to_days() {
393 let y = Years::new(1.0);
394 let day = y.to::<Day>();
395 assert_abs_diff_eq!(day.value(), 365.2425, epsilon = 1e-9);
396 }
397
398 #[test]
399 fn century_to_days() {
400 let c = Centuries::new(1.0);
401 let day = c.to::<Day>();
402 assert_abs_diff_eq!(day.value(), 36524.25, epsilon = 1e-9);
403 }
404
405 #[test]
406 fn milliseconds_to_seconds() {
407 let ms = Milliseconds::new(1000.0);
408 let sec = ms.to::<Second>();
409 assert_abs_diff_eq!(sec.value(), 1.0, epsilon = 1e-9);
410 }
411
412 #[test]
417 fn roundtrip_day_second() {
418 let original = Days::new(1.5);
419 let converted = original.to::<Second>();
420 let back = converted.to::<Day>();
421 assert_abs_diff_eq!(back.value(), original.value(), epsilon = 1e-12);
422 }
423
424 #[test]
425 fn roundtrip_julian_year_day() {
426 let original = JulianYears::new(2.5);
427 let converted = original.to::<Day>();
428 let back = converted.to::<JulianYear>();
429 assert_abs_diff_eq!(back.value(), original.value(), epsilon = 1e-12);
430 }
431
432 #[test]
437 fn second_ratio_sanity() {
438 assert_abs_diff_eq!(Second::RATIO, 1.0, epsilon = 1e-15);
440 }
441
442 #[test]
443 fn minute_ratio_sanity() {
444 assert_abs_diff_eq!(Minute::RATIO, 60.0, epsilon = 1e-15);
446 }
447
448 #[test]
449 fn hour_ratio_sanity() {
450 assert_abs_diff_eq!(Hour::RATIO, 3_600.0, epsilon = 1e-15);
452 }
453
454 proptest! {
459 #[test]
460 fn prop_roundtrip_day_second(d in -1e6..1e6f64) {
461 let original = Days::new(d);
462 let converted = original.to::<Second>();
463 let back = converted.to::<Day>();
464 prop_assert!((back.value() - original.value()).abs() < 1e-9);
465 }
466
467 #[test]
468 fn prop_day_second_ratio(d in 1e-6..1e6f64) {
469 let day = Days::new(d);
470 let sec = day.to::<Second>();
471 prop_assert!((sec.value() / day.value() - 86400.0).abs() < 1e-9);
473 }
474
475 #[test]
476 fn prop_julian_year_day_ratio(y in 1e-6..1e6f64) {
477 let jy = JulianYears::new(y);
478 let day = jy.to::<Day>();
479 prop_assert!((day.value() / jy.value() - 365.25).abs() < 1e-9);
481 }
482 }
483}