use crate::{Quantity, Unit};
use qtty_derive::Unit;
pub use crate::dimension::Time;
pub trait TimeUnit: Unit<Dim = Time> {}
impl<T: Unit<Dim = Time>> TimeUnit for T {}
pub const SECONDS_PER_DAY: f64 = 86_400.0;
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "as", dimension = Time, ratio = 1e-18)]
pub struct Attosecond;
pub type Attoseconds = Quantity<Attosecond>;
pub const ATTOSEC: Attoseconds = Attoseconds::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "fs", dimension = Time, ratio = 1e-15)]
pub struct Femtosecond;
pub type Femtoseconds = Quantity<Femtosecond>;
pub const FEMTOSEC: Femtoseconds = Femtoseconds::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "ps", dimension = Time, ratio = 1e-12)]
pub struct Picosecond;
pub type Picoseconds = Quantity<Picosecond>;
pub const PICOSEC: Picoseconds = Picoseconds::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "ns", dimension = Time, ratio = 1e-9)]
pub struct Nanosecond;
pub type Nanoseconds = Quantity<Nanosecond>;
pub const NANOSEC: Nanoseconds = Nanoseconds::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "µs", dimension = Time, ratio = 1e-6)]
pub struct Microsecond;
pub type Microseconds = Quantity<Microsecond>;
pub const MICROSEC: Microseconds = Microseconds::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "ms", dimension = Time, ratio = 1e-3)]
pub struct Millisecond;
pub type Milliseconds = Quantity<Millisecond>;
pub const MILLISEC: Milliseconds = Milliseconds::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "cs", dimension = Time, ratio = 1e-2)]
pub struct Centisecond;
pub type Centiseconds = Quantity<Centisecond>;
pub const CENTISEC: Centiseconds = Centiseconds::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "ds", dimension = Time, ratio = 1e-1)]
pub struct Decisecond;
pub type Deciseconds = Quantity<Decisecond>;
pub const DECISEC: Deciseconds = Deciseconds::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "s", dimension = Time, ratio = 1.0)]
pub struct Second;
pub type Seconds = Quantity<Second>;
pub const SEC: Seconds = Seconds::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "das", dimension = Time, ratio = 10.0)]
pub struct Decasecond;
pub type Decaseconds = Quantity<Decasecond>;
pub const DECASEC: Decaseconds = Decaseconds::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "hs", dimension = Time, ratio = 100.0)]
pub struct Hectosecond;
pub type Hectoseconds = Quantity<Hectosecond>;
pub const HECTOSEC: Hectoseconds = Hectoseconds::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "ks", dimension = Time, ratio = 1_000.0)]
pub struct Kilosecond;
pub type Kiloseconds = Quantity<Kilosecond>;
pub const KILOSEC: Kiloseconds = Kiloseconds::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "Ms", dimension = Time, ratio = 1e6)]
pub struct Megasecond;
pub type Megaseconds = Quantity<Megasecond>;
pub const MEGASEC: Megaseconds = Megaseconds::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "Gs", dimension = Time, ratio = 1e9)]
pub struct Gigasecond;
pub type Gigaseconds = Quantity<Gigasecond>;
pub const GIGASEC: Gigaseconds = Gigaseconds::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "Ts", dimension = Time, ratio = 1e12)]
pub struct Terasecond;
pub type Teraseconds = Quantity<Terasecond>;
pub const TERASEC: Teraseconds = Teraseconds::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "min", dimension = Time, ratio = 60.0)]
pub struct Minute;
pub type Minutes = Quantity<Minute>;
pub const MIN: Minutes = Minutes::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "h", dimension = Time, ratio = 3_600.0)]
pub struct Hour;
pub type Hours = Quantity<Hour>;
pub const HOUR: Hours = Hours::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "d", dimension = Time, ratio = SECONDS_PER_DAY)]
pub struct Day;
pub type Days = Quantity<Day>;
pub const DAY: Days = Days::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "wk", dimension = Time, ratio = 7.0 * SECONDS_PER_DAY)]
pub struct Week;
pub type Weeks = Quantity<Week>;
pub const WEEK: Weeks = Weeks::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "fn", dimension = Time, ratio = 14.0 * SECONDS_PER_DAY)]
pub struct Fortnight;
pub type Fortnights = Quantity<Fortnight>;
pub const FORTNIGHT: Fortnights = Fortnights::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "yr", dimension = Time, ratio = 365.242_5 * SECONDS_PER_DAY)]
pub struct Year;
pub type Years = Quantity<Year>;
pub const YEAR: Years = Years::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "dec", dimension = Time, ratio = 10.0 * 365.242_5 * SECONDS_PER_DAY)]
pub struct Decade;
pub type Decades = Quantity<Decade>;
pub const DECADE: Decades = Decades::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "cent", dimension = Time, ratio = 100.0 * 365.242_5 * SECONDS_PER_DAY)]
pub struct Century;
pub type Centuries = Quantity<Century>;
pub const CENTURY: Centuries = Centuries::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "mill", dimension = Time, ratio = 1000.0 * 365.242_5 * SECONDS_PER_DAY)]
pub struct Millennium;
pub type Millennia = Quantity<Millennium>;
pub const MILLENNIUM: Millennia = Millennia::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "a", dimension = Time, ratio = 365.25 * SECONDS_PER_DAY)]
pub struct JulianYear;
pub type JulianYears = Quantity<JulianYear>;
pub const JULIAN_YEAR: JulianYears = JulianYears::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "JC", dimension = Time, ratio = 36_525.0 * SECONDS_PER_DAY)]
pub struct JulianCentury;
pub type JulianCenturies = Quantity<JulianCentury>;
pub const JULIAN_CENTURY: JulianCenturies = JulianCenturies::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "sd", dimension = Time, ratio = 86_164.090_5)]
pub struct SiderealDay;
pub type SiderealDays = Quantity<SiderealDay>;
pub const SIDEREAL_DAY: SiderealDays = SiderealDays::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "synmo", dimension = Time, ratio = 29.530_588 * SECONDS_PER_DAY)]
pub struct SynodicMonth;
pub type SynodicMonths = Quantity<SynodicMonth>;
pub const SYNODIC_MONTH: SynodicMonths = SynodicMonths::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "syr", dimension = Time, ratio = 365.256_363_004 * SECONDS_PER_DAY)]
pub struct SiderealYear;
pub type SiderealYears = Quantity<SiderealYear>;
pub const SIDEREAL_YEAR: SiderealYears = SiderealYears::new(1.0);
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_abs_diff_eq;
use proptest::prelude::*;
#[test]
fn seconds_to_minutes() {
let sec = Seconds::new(60.0);
let min = sec.to::<Minute>();
assert_abs_diff_eq!(min.value(), 1.0, epsilon = 1e-12);
}
#[test]
fn minutes_to_hours() {
let min = Minutes::new(60.0);
let hr = min.to::<Hour>();
assert_abs_diff_eq!(hr.value(), 1.0, epsilon = 1e-12);
}
#[test]
fn hours_to_days() {
let hr = Hours::new(24.0);
let day = hr.to::<Day>();
assert_abs_diff_eq!(day.value(), 1.0, epsilon = 1e-12);
}
#[test]
fn seconds_86400_equals_one_day() {
let sec = Seconds::new(86400.0);
let day = sec.to::<Day>();
assert_abs_diff_eq!(day.value(), 1.0, epsilon = 1e-12);
}
#[test]
fn day_to_seconds() {
let day = Days::new(1.0);
let sec = day.to::<Second>();
assert_abs_diff_eq!(sec.value(), 86400.0, epsilon = 1e-9);
}
#[test]
fn days_to_weeks() {
let day = Days::new(7.0);
let week = day.to::<Week>();
assert_abs_diff_eq!(week.value(), 1.0, epsilon = 1e-12);
}
#[test]
fn julian_year_to_days() {
let jy = JulianYears::new(1.0);
let day = jy.to::<Day>();
assert_abs_diff_eq!(day.value(), 365.25, epsilon = 1e-9);
}
#[test]
fn julian_century_to_days() {
let jc = JulianCenturies::new(1.0);
let day = jc.to::<Day>();
assert_abs_diff_eq!(day.value(), 36525.0, epsilon = 1e-9);
}
#[test]
fn julian_century_to_julian_years() {
let jc = JulianCenturies::new(1.0);
let jy = jc.to::<JulianYear>();
assert_abs_diff_eq!(jy.value(), 100.0, epsilon = 1e-9);
}
#[test]
fn tropical_year_to_days() {
let y = Years::new(1.0);
let day = y.to::<Day>();
assert_abs_diff_eq!(day.value(), 365.2425, epsilon = 1e-9);
}
#[test]
fn century_to_days() {
let c = Centuries::new(1.0);
let day = c.to::<Day>();
assert_abs_diff_eq!(day.value(), 36524.25, epsilon = 1e-9);
}
#[test]
fn milliseconds_to_seconds() {
let ms = Milliseconds::new(1000.0);
let sec = ms.to::<Second>();
assert_abs_diff_eq!(sec.value(), 1.0, epsilon = 1e-9);
}
#[test]
fn roundtrip_day_second() {
let original = Days::new(1.5);
let converted = original.to::<Second>();
let back = converted.to::<Day>();
assert_abs_diff_eq!(back.value(), original.value(), epsilon = 1e-12);
}
#[test]
fn roundtrip_julian_year_day() {
let original = JulianYears::new(2.5);
let converted = original.to::<Day>();
let back = converted.to::<JulianYear>();
assert_abs_diff_eq!(back.value(), original.value(), epsilon = 1e-12);
}
#[test]
fn second_ratio_sanity() {
assert_abs_diff_eq!(Second::RATIO, 1.0, epsilon = 1e-15);
}
#[test]
fn minute_ratio_sanity() {
assert_abs_diff_eq!(Minute::RATIO, 60.0, epsilon = 1e-15);
}
#[test]
fn hour_ratio_sanity() {
assert_abs_diff_eq!(Hour::RATIO, 3_600.0, epsilon = 1e-15);
}
proptest! {
#[test]
fn prop_roundtrip_day_second(d in -1e6..1e6f64) {
let original = Days::new(d);
let converted = original.to::<Second>();
let back = converted.to::<Day>();
prop_assert!((back.value() - original.value()).abs() < 1e-9);
}
#[test]
fn prop_day_second_ratio(d in 1e-6..1e6f64) {
let day = Days::new(d);
let sec = day.to::<Second>();
prop_assert!((sec.value() / day.value() - 86400.0).abs() < 1e-9);
}
#[test]
fn prop_julian_year_day_ratio(y in 1e-6..1e6f64) {
let jy = JulianYears::new(y);
let day = jy.to::<Day>();
prop_assert!((day.value() / jy.value() - 365.25).abs() < 1e-9);
}
}
#[test]
fn attosecond_to_second() {
let q = Attoseconds::new(1e18);
let s = q.to::<Second>();
assert_abs_diff_eq!(s.value(), 1.0, epsilon = 1e-9);
}
#[test]
fn femtosecond_to_second() {
let q = Femtoseconds::new(1e15);
let s = q.to::<Second>();
assert_abs_diff_eq!(s.value(), 1.0, epsilon = 1e-9);
}
#[test]
fn picosecond_to_second() {
let q = Picoseconds::new(1e12);
let s = q.to::<Second>();
assert_abs_diff_eq!(s.value(), 1.0, epsilon = 1e-9);
}
#[test]
fn nanosecond_to_second() {
let q = Nanoseconds::new(1e9);
let s = q.to::<Second>();
assert_abs_diff_eq!(s.value(), 1.0, epsilon = 1e-9);
}
#[test]
fn microsecond_to_second() {
let q = Microseconds::new(1e6);
let s = q.to::<Second>();
assert_abs_diff_eq!(s.value(), 1.0, epsilon = 1e-9);
}
#[test]
fn centisecond_to_second() {
let q = Centiseconds::new(100.0);
let s = q.to::<Second>();
assert_abs_diff_eq!(s.value(), 1.0, epsilon = 1e-12);
}
#[test]
fn decisecond_to_second() {
let q = Deciseconds::new(10.0);
let s = q.to::<Second>();
assert_abs_diff_eq!(s.value(), 1.0, epsilon = 1e-12);
}
#[test]
fn decasecond_to_second() {
let q = Decaseconds::new(1.0);
let s = q.to::<Second>();
assert_abs_diff_eq!(s.value(), 10.0, epsilon = 1e-12);
}
#[test]
fn hectosecond_to_second() {
let q = Hectoseconds::new(1.0);
let s = q.to::<Second>();
assert_abs_diff_eq!(s.value(), 100.0, epsilon = 1e-12);
}
#[test]
fn kilosecond_to_second() {
let q = Kiloseconds::new(1.0);
let s = q.to::<Second>();
assert_abs_diff_eq!(s.value(), 1_000.0, epsilon = 1e-12);
}
#[test]
fn megasecond_to_second() {
let q = Megaseconds::new(1.0);
let s = q.to::<Second>();
assert_abs_diff_eq!(s.value(), 1e6, epsilon = 1.0);
}
#[test]
fn gigasecond_to_second() {
let q = Gigaseconds::new(1.0);
let s = q.to::<Second>();
assert_abs_diff_eq!(s.value(), 1e9, epsilon = 1e3);
}
#[test]
fn terasecond_to_second() {
let q = Teraseconds::new(1.0);
let s = q.to::<Second>();
assert_abs_diff_eq!(s.value(), 1e12, epsilon = 1e6);
}
#[test]
fn fortnight_to_days() {
let q = Fortnights::new(1.0);
let d = q.to::<Day>();
assert_abs_diff_eq!(d.value(), 14.0, epsilon = 1e-12);
}
#[test]
fn decade_to_years() {
let q = Decades::new(1.0);
let y = q.to::<Year>();
assert_abs_diff_eq!(y.value(), 10.0, epsilon = 1e-9);
}
#[test]
fn millennium_to_years() {
let q = Millennia::new(1.0);
let y = q.to::<Year>();
assert_abs_diff_eq!(y.value(), 1000.0, epsilon = 1e-9);
}
#[test]
fn sidereal_day_to_seconds() {
let q = SiderealDays::new(1.0);
let s = q.to::<Second>();
assert_abs_diff_eq!(s.value(), 86_164.090_5, epsilon = 1e-3);
}
#[test]
fn synodic_month_to_days() {
let q = SynodicMonths::new(1.0);
let d = q.to::<Day>();
assert_abs_diff_eq!(d.value(), 29.530_588, epsilon = 1e-6);
}
#[test]
fn sidereal_year_to_days() {
let q = SiderealYears::new(1.0);
let d = q.to::<Day>();
assert_abs_diff_eq!(d.value(), 365.256_363_004, epsilon = 1e-6);
}
#[test]
fn symbols_are_correct() {
assert_eq!(format!("{}", Attoseconds::new(1.0)), "1 as");
assert_eq!(format!("{}", Nanoseconds::new(1.0)), "1 ns");
assert_eq!(format!("{}", Kiloseconds::new(1.0)), "1 ks");
assert_eq!(format!("{}", Fortnights::new(1.0)), "1 fn");
assert_eq!(format!("{}", SiderealDays::new(1.0)), "1 sd");
}
}