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}