1use crate::{Quantity, Unit};
56use qtty_derive::Unit;
57
58pub use crate::dimension::Time;
60
61pub trait TimeUnit: Unit<Dim = Time> {}
63impl<T: Unit<Dim = Time>> TimeUnit for T {}
64
65pub const SECONDS_PER_DAY: f64 = 86_400.0;
67
68#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
72#[unit(symbol = "as", dimension = Time, ratio = 1e-18)]
73pub struct Attosecond;
74pub type Attoseconds = Quantity<Attosecond>;
76pub const ATTOSEC: Attoseconds = Attoseconds::new(1.0);
78
79#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
81#[unit(symbol = "fs", dimension = Time, ratio = 1e-15)]
82pub struct Femtosecond;
83pub type Femtoseconds = Quantity<Femtosecond>;
85pub const FEMTOSEC: Femtoseconds = Femtoseconds::new(1.0);
87
88#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
90#[unit(symbol = "ps", dimension = Time, ratio = 1e-12)]
91pub struct Picosecond;
92pub type Picoseconds = Quantity<Picosecond>;
94pub const PICOSEC: Picoseconds = Picoseconds::new(1.0);
96
97#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
99#[unit(symbol = "ns", dimension = Time, ratio = 1e-9)]
100pub struct Nanosecond;
101pub type Nanoseconds = Quantity<Nanosecond>;
103pub const NANOSEC: Nanoseconds = Nanoseconds::new(1.0);
105
106#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
108#[unit(symbol = "µs", dimension = Time, ratio = 1e-6)]
109pub struct Microsecond;
110pub type Microseconds = Quantity<Microsecond>;
112pub const MICROSEC: Microseconds = Microseconds::new(1.0);
114
115#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
117#[unit(symbol = "ms", dimension = Time, ratio = 1e-3)]
118pub struct Millisecond;
119pub type Milliseconds = Quantity<Millisecond>;
121pub const MILLISEC: Milliseconds = Milliseconds::new(1.0);
123
124#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
126#[unit(symbol = "cs", dimension = Time, ratio = 1e-2)]
127pub struct Centisecond;
128pub type Centiseconds = Quantity<Centisecond>;
130pub const CENTISEC: Centiseconds = Centiseconds::new(1.0);
132
133#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
135#[unit(symbol = "ds", dimension = Time, ratio = 1e-1)]
136pub struct Decisecond;
137pub type Deciseconds = Quantity<Decisecond>;
139pub const DECISEC: Deciseconds = Deciseconds::new(1.0);
141
142#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
144#[unit(symbol = "s", dimension = Time, ratio = 1.0)]
145pub struct Second;
146pub type Seconds = Quantity<Second>;
148pub const SEC: Seconds = Seconds::new(1.0);
150
151#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
155#[unit(symbol = "das", dimension = Time, ratio = 10.0)]
156pub struct Decasecond;
157pub type Decaseconds = Quantity<Decasecond>;
159pub const DECASEC: Decaseconds = Decaseconds::new(1.0);
161
162#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
164#[unit(symbol = "hs", dimension = Time, ratio = 100.0)]
165pub struct Hectosecond;
166pub type Hectoseconds = Quantity<Hectosecond>;
168pub const HECTOSEC: Hectoseconds = Hectoseconds::new(1.0);
170
171#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
173#[unit(symbol = "ks", dimension = Time, ratio = 1_000.0)]
174pub struct Kilosecond;
175pub type Kiloseconds = Quantity<Kilosecond>;
177pub const KILOSEC: Kiloseconds = Kiloseconds::new(1.0);
179
180#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
182#[unit(symbol = "Ms", dimension = Time, ratio = 1e6)]
183pub struct Megasecond;
184pub type Megaseconds = Quantity<Megasecond>;
186pub const MEGASEC: Megaseconds = Megaseconds::new(1.0);
188
189#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
191#[unit(symbol = "Gs", dimension = Time, ratio = 1e9)]
192pub struct Gigasecond;
193pub type Gigaseconds = Quantity<Gigasecond>;
195pub const GIGASEC: Gigaseconds = Gigaseconds::new(1.0);
197
198#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
200#[unit(symbol = "Ts", dimension = Time, ratio = 1e12)]
201pub struct Terasecond;
202pub type Teraseconds = Quantity<Terasecond>;
204pub const TERASEC: Teraseconds = Teraseconds::new(1.0);
206
207#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
211#[unit(symbol = "min", dimension = Time, ratio = 60.0)]
212pub struct Minute;
213pub type Minutes = Quantity<Minute>;
215pub const MIN: Minutes = Minutes::new(1.0);
217
218#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
220#[unit(symbol = "h", dimension = Time, ratio = 3_600.0)]
221pub struct Hour;
222pub type Hours = Quantity<Hour>;
224pub const HOUR: Hours = Hours::new(1.0);
226
227#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
229#[unit(symbol = "d", dimension = Time, ratio = SECONDS_PER_DAY)]
230pub struct Day;
231pub type Days = Quantity<Day>;
233pub const DAY: Days = Days::new(1.0);
235
236#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
238#[unit(symbol = "wk", dimension = Time, ratio = 7.0 * SECONDS_PER_DAY)]
239pub struct Week;
240pub type Weeks = Quantity<Week>;
242pub const WEEK: Weeks = Weeks::new(1.0);
244
245#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
247#[unit(symbol = "fn", dimension = Time, ratio = 14.0 * SECONDS_PER_DAY)]
248pub struct Fortnight;
249pub type Fortnights = Quantity<Fortnight>;
251pub const FORTNIGHT: Fortnights = Fortnights::new(1.0);
253
254#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
258#[unit(symbol = "yr", dimension = Time, ratio = 365.242_5 * SECONDS_PER_DAY)]
259pub struct Year;
260pub type Years = Quantity<Year>;
262pub const YEAR: Years = Years::new(1.0);
264
265#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
267#[unit(symbol = "dec", dimension = Time, ratio = 10.0 * 365.242_5 * SECONDS_PER_DAY)]
268pub struct Decade;
269pub type Decades = Quantity<Decade>;
271pub const DECADE: Decades = Decades::new(1.0);
273
274#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
276#[unit(symbol = "cent", dimension = Time, ratio = 100.0 * 365.242_5 * SECONDS_PER_DAY)]
277pub struct Century;
278pub type Centuries = Quantity<Century>;
280pub const CENTURY: Centuries = Centuries::new(1.0);
282
283#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
285#[unit(symbol = "mill", dimension = Time, ratio = 1000.0 * 365.242_5 * SECONDS_PER_DAY)]
286pub struct Millennium;
287pub type Millennia = Quantity<Millennium>;
289pub const MILLENNIUM: Millennia = Millennia::new(1.0);
291
292#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
296#[unit(symbol = "a", dimension = Time, ratio = 365.25 * SECONDS_PER_DAY)]
297pub struct JulianYear;
298pub type JulianYears = Quantity<JulianYear>;
300pub const JULIAN_YEAR: JulianYears = JulianYears::new(1.0);
302
303#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
305#[unit(symbol = "JC", dimension = Time, ratio = 36_525.0 * SECONDS_PER_DAY)]
306pub struct JulianCentury;
307pub type JulianCenturies = Quantity<JulianCentury>;
309pub const JULIAN_CENTURY: JulianCenturies = JulianCenturies::new(1.0);
311
312#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
318#[unit(symbol = "sd", dimension = Time, ratio = 86_164.090_5)]
319pub struct SiderealDay;
320pub type SiderealDays = Quantity<SiderealDay>;
322pub const SIDEREAL_DAY: SiderealDays = SiderealDays::new(1.0);
324
325#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
329#[unit(symbol = "synmo", dimension = Time, ratio = 29.530_588 * SECONDS_PER_DAY)]
330pub struct SynodicMonth;
331pub type SynodicMonths = Quantity<SynodicMonth>;
333pub const SYNODIC_MONTH: SynodicMonths = SynodicMonths::new(1.0);
335
336#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
340#[unit(symbol = "syr", dimension = Time, ratio = 365.256_363_004 * SECONDS_PER_DAY)]
341pub struct SiderealYear;
342pub type SiderealYears = Quantity<SiderealYear>;
344pub const SIDEREAL_YEAR: SiderealYears = SiderealYears::new(1.0);
346
347#[cfg(test)]
348mod tests {
349 use super::*;
350 use approx::assert_abs_diff_eq;
351 use proptest::prelude::*;
352
353 #[test]
358 fn seconds_to_minutes() {
359 let sec = Seconds::new(60.0);
360 let min = sec.to::<Minute>();
361 assert_abs_diff_eq!(min.value(), 1.0, epsilon = 1e-12);
362 }
363
364 #[test]
365 fn minutes_to_hours() {
366 let min = Minutes::new(60.0);
367 let hr = min.to::<Hour>();
368 assert_abs_diff_eq!(hr.value(), 1.0, epsilon = 1e-12);
369 }
370
371 #[test]
372 fn hours_to_days() {
373 let hr = Hours::new(24.0);
374 let day = hr.to::<Day>();
375 assert_abs_diff_eq!(day.value(), 1.0, epsilon = 1e-12);
376 }
377
378 #[test]
379 fn seconds_86400_equals_one_day() {
380 let sec = Seconds::new(86400.0);
381 let day = sec.to::<Day>();
382 assert_abs_diff_eq!(day.value(), 1.0, epsilon = 1e-12);
383 }
384
385 #[test]
386 fn day_to_seconds() {
387 let day = Days::new(1.0);
388 let sec = day.to::<Second>();
389 assert_abs_diff_eq!(sec.value(), 86400.0, epsilon = 1e-9);
390 }
391
392 #[test]
393 fn days_to_weeks() {
394 let day = Days::new(7.0);
395 let week = day.to::<Week>();
396 assert_abs_diff_eq!(week.value(), 1.0, epsilon = 1e-12);
397 }
398
399 #[test]
400 fn julian_year_to_days() {
401 let jy = JulianYears::new(1.0);
402 let day = jy.to::<Day>();
403 assert_abs_diff_eq!(day.value(), 365.25, epsilon = 1e-9);
404 }
405
406 #[test]
407 fn julian_century_to_days() {
408 let jc = JulianCenturies::new(1.0);
409 let day = jc.to::<Day>();
410 assert_abs_diff_eq!(day.value(), 36525.0, epsilon = 1e-9);
411 }
412
413 #[test]
414 fn julian_century_to_julian_years() {
415 let jc = JulianCenturies::new(1.0);
416 let jy = jc.to::<JulianYear>();
417 assert_abs_diff_eq!(jy.value(), 100.0, epsilon = 1e-9);
418 }
419
420 #[test]
421 fn tropical_year_to_days() {
422 let y = Years::new(1.0);
423 let day = y.to::<Day>();
424 assert_abs_diff_eq!(day.value(), 365.2425, epsilon = 1e-9);
425 }
426
427 #[test]
428 fn century_to_days() {
429 let c = Centuries::new(1.0);
430 let day = c.to::<Day>();
431 assert_abs_diff_eq!(day.value(), 36524.25, epsilon = 1e-9);
432 }
433
434 #[test]
435 fn milliseconds_to_seconds() {
436 let ms = Milliseconds::new(1000.0);
437 let sec = ms.to::<Second>();
438 assert_abs_diff_eq!(sec.value(), 1.0, epsilon = 1e-9);
439 }
440
441 #[test]
446 fn roundtrip_day_second() {
447 let original = Days::new(1.5);
448 let converted = original.to::<Second>();
449 let back = converted.to::<Day>();
450 assert_abs_diff_eq!(back.value(), original.value(), epsilon = 1e-12);
451 }
452
453 #[test]
454 fn roundtrip_julian_year_day() {
455 let original = JulianYears::new(2.5);
456 let converted = original.to::<Day>();
457 let back = converted.to::<JulianYear>();
458 assert_abs_diff_eq!(back.value(), original.value(), epsilon = 1e-12);
459 }
460
461 #[test]
466 fn second_ratio_sanity() {
467 assert_abs_diff_eq!(Second::RATIO, 1.0, epsilon = 1e-15);
469 }
470
471 #[test]
472 fn minute_ratio_sanity() {
473 assert_abs_diff_eq!(Minute::RATIO, 60.0, epsilon = 1e-15);
475 }
476
477 #[test]
478 fn hour_ratio_sanity() {
479 assert_abs_diff_eq!(Hour::RATIO, 3_600.0, epsilon = 1e-15);
481 }
482
483 proptest! {
488 #[test]
489 fn prop_roundtrip_day_second(d in -1e6..1e6f64) {
490 let original = Days::new(d);
491 let converted = original.to::<Second>();
492 let back = converted.to::<Day>();
493 prop_assert!((back.value() - original.value()).abs() < 1e-9);
494 }
495
496 #[test]
497 fn prop_day_second_ratio(d in 1e-6..1e6f64) {
498 let day = Days::new(d);
499 let sec = day.to::<Second>();
500 prop_assert!((sec.value() / day.value() - 86400.0).abs() < 1e-9);
502 }
503
504 #[test]
505 fn prop_julian_year_day_ratio(y in 1e-6..1e6f64) {
506 let jy = JulianYears::new(y);
507 let day = jy.to::<Day>();
508 prop_assert!((day.value() / jy.value() - 365.25).abs() < 1e-9);
510 }
511 }
512
513 #[test]
516 fn attosecond_to_second() {
517 let q = Attoseconds::new(1e18);
518 let s = q.to::<Second>();
519 assert_abs_diff_eq!(s.value(), 1.0, epsilon = 1e-9);
520 }
521
522 #[test]
523 fn femtosecond_to_second() {
524 let q = Femtoseconds::new(1e15);
525 let s = q.to::<Second>();
526 assert_abs_diff_eq!(s.value(), 1.0, epsilon = 1e-9);
527 }
528
529 #[test]
530 fn picosecond_to_second() {
531 let q = Picoseconds::new(1e12);
532 let s = q.to::<Second>();
533 assert_abs_diff_eq!(s.value(), 1.0, epsilon = 1e-9);
534 }
535
536 #[test]
537 fn nanosecond_to_second() {
538 let q = Nanoseconds::new(1e9);
539 let s = q.to::<Second>();
540 assert_abs_diff_eq!(s.value(), 1.0, epsilon = 1e-9);
541 }
542
543 #[test]
544 fn microsecond_to_second() {
545 let q = Microseconds::new(1e6);
546 let s = q.to::<Second>();
547 assert_abs_diff_eq!(s.value(), 1.0, epsilon = 1e-9);
548 }
549
550 #[test]
551 fn centisecond_to_second() {
552 let q = Centiseconds::new(100.0);
553 let s = q.to::<Second>();
554 assert_abs_diff_eq!(s.value(), 1.0, epsilon = 1e-12);
555 }
556
557 #[test]
558 fn decisecond_to_second() {
559 let q = Deciseconds::new(10.0);
560 let s = q.to::<Second>();
561 assert_abs_diff_eq!(s.value(), 1.0, epsilon = 1e-12);
562 }
563
564 #[test]
567 fn decasecond_to_second() {
568 let q = Decaseconds::new(1.0);
569 let s = q.to::<Second>();
570 assert_abs_diff_eq!(s.value(), 10.0, epsilon = 1e-12);
571 }
572
573 #[test]
574 fn hectosecond_to_second() {
575 let q = Hectoseconds::new(1.0);
576 let s = q.to::<Second>();
577 assert_abs_diff_eq!(s.value(), 100.0, epsilon = 1e-12);
578 }
579
580 #[test]
581 fn kilosecond_to_second() {
582 let q = Kiloseconds::new(1.0);
583 let s = q.to::<Second>();
584 assert_abs_diff_eq!(s.value(), 1_000.0, epsilon = 1e-12);
585 }
586
587 #[test]
588 fn megasecond_to_second() {
589 let q = Megaseconds::new(1.0);
590 let s = q.to::<Second>();
591 assert_abs_diff_eq!(s.value(), 1e6, epsilon = 1.0);
592 }
593
594 #[test]
595 fn gigasecond_to_second() {
596 let q = Gigaseconds::new(1.0);
597 let s = q.to::<Second>();
598 assert_abs_diff_eq!(s.value(), 1e9, epsilon = 1e3);
599 }
600
601 #[test]
602 fn terasecond_to_second() {
603 let q = Teraseconds::new(1.0);
604 let s = q.to::<Second>();
605 assert_abs_diff_eq!(s.value(), 1e12, epsilon = 1e6);
606 }
607
608 #[test]
611 fn fortnight_to_days() {
612 let q = Fortnights::new(1.0);
613 let d = q.to::<Day>();
614 assert_abs_diff_eq!(d.value(), 14.0, epsilon = 1e-12);
615 }
616
617 #[test]
618 fn decade_to_years() {
619 let q = Decades::new(1.0);
620 let y = q.to::<Year>();
621 assert_abs_diff_eq!(y.value(), 10.0, epsilon = 1e-9);
622 }
623
624 #[test]
625 fn millennium_to_years() {
626 let q = Millennia::new(1.0);
627 let y = q.to::<Year>();
628 assert_abs_diff_eq!(y.value(), 1000.0, epsilon = 1e-9);
629 }
630
631 #[test]
634 fn sidereal_day_to_seconds() {
635 let q = SiderealDays::new(1.0);
636 let s = q.to::<Second>();
637 assert_abs_diff_eq!(s.value(), 86_164.090_5, epsilon = 1e-3);
639 }
640
641 #[test]
642 fn synodic_month_to_days() {
643 let q = SynodicMonths::new(1.0);
644 let d = q.to::<Day>();
645 assert_abs_diff_eq!(d.value(), 29.530_588, epsilon = 1e-6);
647 }
648
649 #[test]
650 fn sidereal_year_to_days() {
651 let q = SiderealYears::new(1.0);
652 let d = q.to::<Day>();
653 assert_abs_diff_eq!(d.value(), 365.256_363_004, epsilon = 1e-6);
655 }
656
657 #[test]
660 fn symbols_are_correct() {
661 assert_eq!(format!("{}", Attoseconds::new(1.0)), "1 as");
662 assert_eq!(format!("{}", Nanoseconds::new(1.0)), "1 ns");
663 assert_eq!(format!("{}", Kiloseconds::new(1.0)), "1 ks");
664 assert_eq!(format!("{}", Fortnights::new(1.0)), "1 fn");
665 assert_eq!(format!("{}", SiderealDays::new(1.0)), "1 sd");
666 }
667}