Skip to main content

lox_core/time/
julian_dates.rs

1// SPDX-FileCopyrightText: 2024 Angus Morrison <github@angus-morrison.com>
2// SPDX-FileCopyrightText: 2024 Helge Eichhorn <git@helgeeichhorn.de>
3//
4// SPDX-License-Identifier: MPL-2.0
5
6/*!
7    Module `julian_dates` exposes the [JulianDate] trait for expressing arbitrary time
8    representations as Julian dates relative to standard [Epoch]s and in a variety of [Unit]s.
9*/
10
11use crate::i64::consts::SECONDS_BETWEEN_JD_AND_J2000;
12
13use super::deltas::TimeDelta;
14
15/// 4713 BC January 1 12:00
16pub const J0: TimeDelta = TimeDelta::from_seconds(-SECONDS_BETWEEN_JD_AND_J2000);
17
18/// The Julian epochs supported by Lox.
19#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
20pub enum Epoch {
21    /// Julian Date epoch (JD 0 = 4713 BC January 1 12:00).
22    JulianDate,
23    /// Modified Julian Date epoch (MJD 0 = 1858 November 17 00:00).
24    ModifiedJulianDate,
25    /// J1950 epoch (1950 January 1 12:00).
26    J1950,
27    /// J2000 epoch (2000 January 1 12:00).
28    J2000,
29}
30
31/// The units of time in which a Julian date may be expressed.
32#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
33pub enum Unit {
34    /// Seconds.
35    Seconds,
36    /// Days (86400 seconds).
37    Days,
38    /// Julian years (365.25 days).
39    Years,
40    /// Julian centuries (36525 days).
41    Centuries,
42}
43
44/// Enables a time or date type to be expressed as a Julian date.
45pub trait JulianDate {
46    /// Expresses `self` as a Julian date in the specified [Unit], relative to the given [Epoch].
47    ///
48    /// This is the only required method for implementing the [JulianDate] trait.
49    fn julian_date(&self, epoch: Epoch, unit: Unit) -> f64;
50
51    /// Expresses `self` as a two-part Julian date in the specified [Unit], relative to the given
52    /// [Epoch].
53    ///
54    /// The default implementation calls [JulianDate::julian_date] and returns the integer and
55    /// fractional parts of the single `f64` result. Applications that cannot afford the associated
56    /// loss of precision should provide their own implementations.
57    fn two_part_julian_date(&self) -> (f64, f64) {
58        let jd = self.julian_date(Epoch::JulianDate, Unit::Days);
59        (jd.trunc(), jd.fract())
60    }
61
62    /// Returns the number of seconds since the Julian epoch as an `f64`.
63    fn seconds_since_julian_epoch(&self) -> f64 {
64        self.julian_date(Epoch::JulianDate, Unit::Seconds)
65    }
66
67    /// Returns the number of seconds since the Modified Julian epoch as an `f64`.
68    fn seconds_since_modified_julian_epoch(&self) -> f64 {
69        self.julian_date(Epoch::ModifiedJulianDate, Unit::Seconds)
70    }
71
72    /// Returns the number of seconds since J1950 as an `f64`.
73    fn seconds_since_j1950(&self) -> f64 {
74        self.julian_date(Epoch::J1950, Unit::Seconds)
75    }
76
77    /// Returns the number of seconds since J2000 as an `f64`.
78    fn seconds_since_j2000(&self) -> f64 {
79        self.julian_date(Epoch::J2000, Unit::Seconds)
80    }
81
82    /// Returns the number of days since the Julian epoch as an `f64`.
83    fn days_since_julian_epoch(&self) -> f64 {
84        self.julian_date(Epoch::JulianDate, Unit::Days)
85    }
86
87    /// Returns the number of days since the Modified Julian epoch as an `f64`.
88    fn days_since_modified_julian_epoch(&self) -> f64 {
89        self.julian_date(Epoch::ModifiedJulianDate, Unit::Days)
90    }
91
92    /// Returns the number of days since J1950 as an `f64`.
93    fn days_since_j1950(&self) -> f64 {
94        self.julian_date(Epoch::J1950, Unit::Days)
95    }
96
97    /// Returns the number of days since J2000 as an `f64`.
98    fn days_since_j2000(&self) -> f64 {
99        self.julian_date(Epoch::J2000, Unit::Days)
100    }
101
102    /// Returns the number of years since the Julian epoch as an `f64`.
103    fn years_since_julian_epoch(&self) -> f64 {
104        self.julian_date(Epoch::JulianDate, Unit::Years)
105    }
106
107    /// Returns the number of years since the Modified Julian epoch as an `f64`.
108    fn years_since_modified_julian_epoch(&self) -> f64 {
109        self.julian_date(Epoch::ModifiedJulianDate, Unit::Years)
110    }
111
112    /// Returns the number of years since J1950 as an `f64`.
113    fn years_since_j1950(&self) -> f64 {
114        self.julian_date(Epoch::J1950, Unit::Years)
115    }
116
117    /// Returns the number of years since J2000 as an `f64`.
118    fn years_since_j2000(&self) -> f64 {
119        self.julian_date(Epoch::J2000, Unit::Years)
120    }
121
122    /// Returns the number of centuries since the Julian epoch as an `f64`.
123    fn centuries_since_julian_epoch(&self) -> f64 {
124        self.julian_date(Epoch::JulianDate, Unit::Centuries)
125    }
126
127    /// Returns the number of centuries since the Modified Julian epoch as an `f64`.
128    fn centuries_since_modified_julian_epoch(&self) -> f64 {
129        self.julian_date(Epoch::ModifiedJulianDate, Unit::Centuries)
130    }
131
132    /// Returns the number of centuries since J1950 as an `f64`.
133    fn centuries_since_j1950(&self) -> f64 {
134        self.julian_date(Epoch::J1950, Unit::Centuries)
135    }
136
137    /// Returns the number of centuries since J2000 as an `f64`.
138    fn centuries_since_j2000(&self) -> f64 {
139        self.julian_date(Epoch::J2000, Unit::Centuries)
140    }
141}