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
68pub const DAYS_PER_GREGORIAN_YEAR: f64 = 365.242_5;
71
72#[cfg(feature = "julian-time")]
73mod julian_time;
74#[cfg(feature = "julian-time")]
75pub use julian_time::*;
76#[cfg(feature = "astro")]
77mod astro;
78#[cfg(feature = "astro")]
79pub use astro::*;
80
81#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
85#[unit(symbol = "as", dimension = Time, ratio = 1e-18)]
86pub struct Attosecond;
87pub type Attoseconds = Quantity<Attosecond>;
89pub const ATTOSEC: Attoseconds = Attoseconds::new(1.0);
91
92#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
94#[unit(symbol = "fs", dimension = Time, ratio = 1e-15)]
95pub struct Femtosecond;
96pub type Femtoseconds = Quantity<Femtosecond>;
98pub const FEMTOSEC: Femtoseconds = Femtoseconds::new(1.0);
100
101#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
103#[unit(symbol = "ps", dimension = Time, ratio = 1e-12)]
104pub struct Picosecond;
105pub type Picoseconds = Quantity<Picosecond>;
107pub const PICOSEC: Picoseconds = Picoseconds::new(1.0);
109
110#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
112#[unit(symbol = "ns", dimension = Time, ratio = 1e-9)]
113pub struct Nanosecond;
114pub type Nanoseconds = Quantity<Nanosecond>;
116pub const NANOSEC: Nanoseconds = Nanoseconds::new(1.0);
118
119#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
121#[unit(symbol = "µs", dimension = Time, ratio = 1e-6)]
122pub struct Microsecond;
123pub type Microseconds = Quantity<Microsecond>;
125pub const MICROSEC: Microseconds = Microseconds::new(1.0);
127
128#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
130#[unit(symbol = "ms", dimension = Time, ratio = 1e-3)]
131pub struct Millisecond;
132pub type Milliseconds = Quantity<Millisecond>;
134pub const MILLISEC: Milliseconds = Milliseconds::new(1.0);
136
137#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
139#[unit(symbol = "cs", dimension = Time, ratio = 1e-2)]
140pub struct Centisecond;
141pub type Centiseconds = Quantity<Centisecond>;
143pub const CENTISEC: Centiseconds = Centiseconds::new(1.0);
145
146#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
148#[unit(symbol = "ds", dimension = Time, ratio = 1e-1)]
149pub struct Decisecond;
150pub type Deciseconds = Quantity<Decisecond>;
152pub const DECISEC: Deciseconds = Deciseconds::new(1.0);
154
155#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
157#[unit(symbol = "s", dimension = Time, ratio = 1.0)]
158pub struct Second;
159pub type Seconds = Quantity<Second>;
161pub const SEC: Seconds = Seconds::new(1.0);
163
164#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
168#[unit(symbol = "das", dimension = Time, ratio = 10.0)]
169pub struct Decasecond;
170pub type Decaseconds = Quantity<Decasecond>;
172pub const DECASEC: Decaseconds = Decaseconds::new(1.0);
174
175#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
177#[unit(symbol = "hs", dimension = Time, ratio = 100.0)]
178pub struct Hectosecond;
179pub type Hectoseconds = Quantity<Hectosecond>;
181pub const HECTOSEC: Hectoseconds = Hectoseconds::new(1.0);
183
184#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
186#[unit(symbol = "ks", dimension = Time, ratio = 1_000.0)]
187pub struct Kilosecond;
188pub type Kiloseconds = Quantity<Kilosecond>;
190pub const KILOSEC: Kiloseconds = Kiloseconds::new(1.0);
192
193#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
195#[unit(symbol = "Ms", dimension = Time, ratio = 1e6)]
196pub struct Megasecond;
197pub type Megaseconds = Quantity<Megasecond>;
199pub const MEGASEC: Megaseconds = Megaseconds::new(1.0);
201
202#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
204#[unit(symbol = "Gs", dimension = Time, ratio = 1e9)]
205pub struct Gigasecond;
206pub type Gigaseconds = Quantity<Gigasecond>;
208pub const GIGASEC: Gigaseconds = Gigaseconds::new(1.0);
210
211#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
213#[unit(symbol = "Ts", dimension = Time, ratio = 1e12)]
214pub struct Terasecond;
215pub type Teraseconds = Quantity<Terasecond>;
217pub const TERASEC: Teraseconds = Teraseconds::new(1.0);
219
220#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
224#[unit(symbol = "min", dimension = Time, ratio = 60.0)]
225pub struct Minute;
226pub type Minutes = Quantity<Minute>;
228pub const MIN: Minutes = Minutes::new(1.0);
230
231#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
233#[unit(symbol = "h", dimension = Time, ratio = 3_600.0)]
234pub struct Hour;
235pub type Hours = Quantity<Hour>;
237pub const HOUR: Hours = Hours::new(1.0);
239
240#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
242#[unit(symbol = "d", dimension = Time, ratio = SECONDS_PER_DAY)]
243pub struct Day;
244pub type Days = Quantity<Day>;
246pub const DAY: Days = Days::new(1.0);
248
249#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
251#[unit(symbol = "wk", dimension = Time, ratio = 7.0 * SECONDS_PER_DAY)]
252pub struct Week;
253pub type Weeks = Quantity<Week>;
255pub const WEEK: Weeks = Weeks::new(1.0);
257
258#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
260#[unit(symbol = "fn", dimension = Time, ratio = 14.0 * SECONDS_PER_DAY)]
261pub struct Fortnight;
262pub type Fortnights = Quantity<Fortnight>;
264pub const FORTNIGHT: Fortnights = Fortnights::new(1.0);
266
267#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
274#[unit(symbol = "yr", dimension = Time, ratio = DAYS_PER_GREGORIAN_YEAR * SECONDS_PER_DAY)]
275pub struct Year;
276pub type Years = Quantity<Year>;
278pub const YEAR: Years = Years::new(1.0);
280
281#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
283#[unit(symbol = "dec", dimension = Time, ratio = 10.0 * DAYS_PER_GREGORIAN_YEAR * SECONDS_PER_DAY)]
284pub struct Decade;
285pub type Decades = Quantity<Decade>;
287pub const DECADE: Decades = Decades::new(1.0);
289
290#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
292#[unit(symbol = "c", dimension = Time, ratio = 100.0 * DAYS_PER_GREGORIAN_YEAR * SECONDS_PER_DAY)]
293pub struct Century;
294pub type Centuries = Quantity<Century>;
296pub const CENTURY: Centuries = Centuries::new(1.0);
298
299#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
301#[unit(symbol = "mill", dimension = Time, ratio = 1000.0 * DAYS_PER_GREGORIAN_YEAR * SECONDS_PER_DAY)]
302pub struct Millennium;
303pub type Millennia = Quantity<Millennium>;
305pub const MILLENNIUM: Millennia = Millennia::new(1.0);
307
308#[macro_export]
314#[doc(hidden)]
315macro_rules! time_units {
316 ($cb:path) => {
317 $cb!(
318 Attosecond,
319 Femtosecond,
320 Picosecond,
321 Nanosecond,
322 Microsecond,
323 Millisecond,
324 Centisecond,
325 Decisecond,
326 Second,
327 Decasecond,
328 Hectosecond,
329 Kilosecond,
330 Megasecond,
331 Gigasecond,
332 Terasecond,
333 Minute,
334 Hour,
335 Day,
336 Week,
337 Fortnight,
338 Year,
339 Decade,
340 Century,
341 Millennium
342 );
343 };
344}
345
346time_units!(crate::impl_unit_from_conversions);
348
349#[cfg(feature = "cross-unit-ops")]
351time_units!(crate::impl_unit_cross_unit_ops);
352
353#[cfg(all(feature = "astro", feature = "julian-time"))]
355crate::__impl_from_each_extra_to_bases!(
356 {SiderealDay, SynodicMonth, SiderealYear}
357 JulianYear, JulianCentury
358);
359
360#[cfg(all(feature = "astro", feature = "julian-time", feature = "cross-unit-ops"))]
361crate::__impl_cross_ops_each_extra_to_bases!(
362 {SiderealDay, SynodicMonth, SiderealYear}
363 JulianYear, JulianCentury
364);
365
366#[cfg(test)]
368time_units!(crate::assert_units_are_builtin);
369
370#[cfg(all(test, feature = "std"))]
371mod tests {
372 use super::*;
373 use approx::assert_abs_diff_eq;
374 use proptest::prelude::*;
375
376 #[test]
381 fn seconds_to_minutes() {
382 let sec = Seconds::new(60.0);
383 let min = sec.to::<Minute>();
384 assert_abs_diff_eq!(min.value(), 1.0, epsilon = 1e-12);
385 }
386
387 #[test]
388 fn minutes_to_hours() {
389 let min = Minutes::new(60.0);
390 let hr = min.to::<Hour>();
391 assert_abs_diff_eq!(hr.value(), 1.0, epsilon = 1e-12);
392 }
393
394 #[test]
395 fn hours_to_days() {
396 let hr = Hours::new(24.0);
397 let day = hr.to::<Day>();
398 assert_abs_diff_eq!(day.value(), 1.0, epsilon = 1e-12);
399 }
400
401 #[test]
402 fn seconds_86400_equals_one_day() {
403 let sec = Seconds::new(86400.0);
404 let day = sec.to::<Day>();
405 assert_abs_diff_eq!(day.value(), 1.0, epsilon = 1e-12);
406 }
407
408 #[test]
409 fn day_to_seconds() {
410 let day = Days::new(1.0);
411 let sec = day.to::<Second>();
412 assert_abs_diff_eq!(sec.value(), 86400.0, epsilon = 1e-9);
413 }
414
415 #[test]
416 fn days_to_weeks() {
417 let day = Days::new(7.0);
418 let week = day.to::<Week>();
419 assert_abs_diff_eq!(week.value(), 1.0, epsilon = 1e-12);
420 }
421
422 #[cfg(feature = "julian-time")]
423 #[test]
424 fn julian_year_to_days() {
425 let jy = JulianYears::new(1.0);
426 let day = jy.to::<Day>();
427 assert_abs_diff_eq!(day.value(), 365.25, epsilon = 1e-9);
428 }
429
430 #[cfg(feature = "julian-time")]
431 #[test]
432 fn julian_century_to_days() {
433 let jc = JulianCenturies::new(1.0);
434 let day = jc.to::<Day>();
435 assert_abs_diff_eq!(day.value(), 36525.0, epsilon = 1e-9);
436 }
437
438 #[cfg(feature = "julian-time")]
439 #[test]
440 fn julian_century_to_julian_years() {
441 let jc = JulianCenturies::new(1.0);
442 let jy = jc.to::<JulianYear>();
443 assert_abs_diff_eq!(jy.value(), 100.0, epsilon = 1e-9);
444 }
445
446 #[test]
447 fn tropical_year_to_days() {
448 let y = Years::new(1.0);
449 let day = y.to::<Day>();
450 assert_abs_diff_eq!(day.value(), 365.242_5, epsilon = 1e-9);
451 }
452
453 #[test]
454 fn century_to_days() {
455 let c = Centuries::new(1.0);
456 let day = c.to::<Day>();
457 assert_abs_diff_eq!(day.value(), 36524.25, epsilon = 1e-9);
458 }
459
460 #[test]
461 fn milliseconds_to_seconds() {
462 let ms = Milliseconds::new(1000.0);
463 let sec = ms.to::<Second>();
464 assert_abs_diff_eq!(sec.value(), 1.0, epsilon = 1e-9);
465 }
466
467 #[test]
472 fn roundtrip_day_second() {
473 let original = Days::new(1.5);
474 let converted = original.to::<Second>();
475 let back = converted.to::<Day>();
476 assert_abs_diff_eq!(back.value(), original.value(), epsilon = 1e-12);
477 }
478
479 #[cfg(feature = "julian-time")]
480 #[test]
481 fn roundtrip_julian_year_day() {
482 let original = JulianYears::new(2.5);
483 let converted = original.to::<Day>();
484 let back = converted.to::<JulianYear>();
485 assert_abs_diff_eq!(back.value(), original.value(), epsilon = 1e-12);
486 }
487
488 #[test]
493 fn second_ratio_sanity() {
494 assert_abs_diff_eq!(Second::RATIO, 1.0, epsilon = 1e-15);
496 }
497
498 #[test]
499 fn minute_ratio_sanity() {
500 assert_abs_diff_eq!(Minute::RATIO, 60.0, epsilon = 1e-15);
502 }
503
504 #[test]
505 fn hour_ratio_sanity() {
506 assert_abs_diff_eq!(Hour::RATIO, 3_600.0, epsilon = 1e-15);
508 }
509
510 proptest! {
515 #[test]
516 fn prop_roundtrip_day_second(d in -1e6..1e6f64) {
517 let original = Days::new(d);
518 let converted = original.to::<Second>();
519 let back = converted.to::<Day>();
520 prop_assert!((back.value() - original.value()).abs() < 1e-9);
521 }
522
523 #[test]
524 fn prop_day_second_ratio(d in 1e-6..1e6f64) {
525 let day = Days::new(d);
526 let sec = day.to::<Second>();
527 prop_assert!((sec.value() / day.value() - 86400.0).abs() < 1e-9);
529 }
530
531 }
532
533 #[cfg(feature = "julian-time")]
534 proptest! {
535 #[test]
536 fn prop_julian_year_day_ratio(y in 1e-6..1e6f64) {
537 let jy = JulianYears::new(y);
538 let day = jy.to::<Day>();
539 prop_assert!((day.value() / jy.value() - 365.25).abs() < 1e-9);
541 }
542 }
543
544 #[test]
547 fn attosecond_to_second() {
548 let q = Attoseconds::new(1e18);
549 let s = q.to::<Second>();
550 assert_abs_diff_eq!(s.value(), 1.0, epsilon = 1e-9);
551 }
552
553 #[test]
554 fn femtosecond_to_second() {
555 let q = Femtoseconds::new(1e15);
556 let s = q.to::<Second>();
557 assert_abs_diff_eq!(s.value(), 1.0, epsilon = 1e-9);
558 }
559
560 #[test]
561 fn picosecond_to_second() {
562 let q = Picoseconds::new(1e12);
563 let s = q.to::<Second>();
564 assert_abs_diff_eq!(s.value(), 1.0, epsilon = 1e-9);
565 }
566
567 #[test]
568 fn nanosecond_to_second() {
569 let q = Nanoseconds::new(1e9);
570 let s = q.to::<Second>();
571 assert_abs_diff_eq!(s.value(), 1.0, epsilon = 1e-9);
572 }
573
574 #[test]
575 fn microsecond_to_second() {
576 let q = Microseconds::new(1e6);
577 let s = q.to::<Second>();
578 assert_abs_diff_eq!(s.value(), 1.0, epsilon = 1e-9);
579 }
580
581 #[test]
582 fn centisecond_to_second() {
583 let q = Centiseconds::new(100.0);
584 let s = q.to::<Second>();
585 assert_abs_diff_eq!(s.value(), 1.0, epsilon = 1e-12);
586 }
587
588 #[test]
589 fn decisecond_to_second() {
590 let q = Deciseconds::new(10.0);
591 let s = q.to::<Second>();
592 assert_abs_diff_eq!(s.value(), 1.0, epsilon = 1e-12);
593 }
594
595 #[test]
598 fn decasecond_to_second() {
599 let q = Decaseconds::new(1.0);
600 let s = q.to::<Second>();
601 assert_abs_diff_eq!(s.value(), 10.0, epsilon = 1e-12);
602 }
603
604 #[test]
605 fn hectosecond_to_second() {
606 let q = Hectoseconds::new(1.0);
607 let s = q.to::<Second>();
608 assert_abs_diff_eq!(s.value(), 100.0, epsilon = 1e-12);
609 }
610
611 #[test]
612 fn kilosecond_to_second() {
613 let q = Kiloseconds::new(1.0);
614 let s = q.to::<Second>();
615 assert_abs_diff_eq!(s.value(), 1_000.0, epsilon = 1e-12);
616 }
617
618 #[test]
619 fn megasecond_to_second() {
620 let q = Megaseconds::new(1.0);
621 let s = q.to::<Second>();
622 assert_abs_diff_eq!(s.value(), 1e6, epsilon = 1.0);
623 }
624
625 #[test]
626 fn gigasecond_to_second() {
627 let q = Gigaseconds::new(1.0);
628 let s = q.to::<Second>();
629 assert_abs_diff_eq!(s.value(), 1e9, epsilon = 1e3);
630 }
631
632 #[test]
633 fn terasecond_to_second() {
634 let q = Teraseconds::new(1.0);
635 let s = q.to::<Second>();
636 assert_abs_diff_eq!(s.value(), 1e12, epsilon = 1e6);
637 }
638
639 #[test]
642 fn fortnight_to_days() {
643 let q = Fortnights::new(1.0);
644 let d = q.to::<Day>();
645 assert_abs_diff_eq!(d.value(), 14.0, epsilon = 1e-12);
646 }
647
648 #[test]
649 fn decade_to_years() {
650 let q = Decades::new(1.0);
651 let y = q.to::<Year>();
652 assert_abs_diff_eq!(y.value(), 10.0, epsilon = 1e-9);
653 }
654
655 #[test]
656 fn millennium_to_years() {
657 let q = Millennia::new(1.0);
658 let y = q.to::<Year>();
659 assert_abs_diff_eq!(y.value(), 1000.0, epsilon = 1e-9);
660 }
661
662 #[cfg(feature = "astro")]
665 #[test]
666 fn sidereal_day_to_seconds() {
667 let q = SiderealDays::new(1.0);
668 let s = q.to::<Second>();
669 assert_abs_diff_eq!(s.value(), 86_164.090_5, epsilon = 1e-3);
671 }
672
673 #[cfg(feature = "astro")]
674 #[test]
675 fn synodic_month_to_days() {
676 let q = SynodicMonths::new(1.0);
677 let d = q.to::<Day>();
678 assert_abs_diff_eq!(d.value(), 29.530_590, epsilon = 1e-6);
680 }
681
682 #[cfg(feature = "astro")]
683 #[test]
684 fn sidereal_year_to_days() {
685 let q = SiderealYears::new(1.0);
686 let d = q.to::<Day>();
687 assert_abs_diff_eq!(d.value(), 365.256_363_004, epsilon = 1e-6);
689 }
690
691 #[test]
694 fn symbols_are_correct() {
695 assert_eq!(format!("{}", Attoseconds::new(1.0)), "1 as");
696 assert_eq!(format!("{}", Nanoseconds::new(1.0)), "1 ns");
697 assert_eq!(format!("{}", Kiloseconds::new(1.0)), "1 ks");
698 assert_eq!(format!("{}", Fortnights::new(1.0)), "1 fn");
699 }
700
701 #[cfg(feature = "astro")]
702 #[test]
703 fn astro_symbols_are_correct() {
704 assert_eq!(format!("{}", SiderealDays::new(1.0)), "1 sd");
705 }
706}