1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
// SPDX-License-Identifier: MIT
// Copyright 2023 IROX Contributors
//!
//! Contains [`JulianDate`] and others - ways of measuring a discrete amount of days from a specific
//! Julian [`Epoch`]
//!
use std::marker::PhantomData;
use crate::{
epoch::{Epoch, UnixTimestamp, COMMON_ERA_EPOCH, GREGORIAN_EPOCH},
gregorian::Date,
SECONDS_IN_DAY,
};
//
/// The Julian Epoch, 01-JAN 4713 BC
pub const JULIAN_EPOCH: Epoch = Epoch(Date {
year: -4713,
day_of_year: 1,
});
///
/// The Reduced Julian Epoch, 16-NOV-1858
///
/// 2400000 JD after the [`JULIAN_EPOCH`]
pub const REDUCED_JULIAN_EPOCH: Epoch = Epoch(Date {
year: 1858,
day_of_year: 320,
});
///
/// The Truncated Julian Epoch, used by NASA, 24-MAY-1968
///
/// 2440000.5 JD after the [`JULIAN_EPOCH`]
pub const TRUNCATED_JULIAN_EPOCH: Epoch = Epoch(Date {
year: 1968,
day_of_year: 145,
});
///
/// A Julian Date represents a number of days (86400 seconds) since a particular
/// Epoch.
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
pub struct JulianDayNumber<T> {
epoch: Epoch,
day_number: f64,
_phantom: PhantomData<T>,
}
impl<T> JulianDayNumber<T> {
pub fn new(epoch: Epoch, day_number: f64) -> Self {
JulianDayNumber {
epoch,
day_number,
_phantom: Default::default(),
}
}
pub fn get_day_number(&self) -> f64 {
self.day_number
}
pub fn get_epoch(&self) -> Epoch {
self.epoch
}
}
/// No functionality, used as a static compile-time type check
pub struct JulianEpoch;
/// No functionality, used as a static compile-time type check
pub struct ReducedJulianEpoch;
/// No functionality, used as a static compile-time type check
pub struct ModifiedJulianEpoch;
/// No functionality, used as a static compile-time type check
pub struct TruncatedJulianEpoch;
/// No functionality, used as a static compile-time type check
pub struct LilianEpoch;
/// No functionality, used as a static compile-time type check
pub struct RataDieEpoch;
///
/// The Julian Date is the number of days since the [`JULIAN_EPOCH`]
///
/// Noon 12:00 on 01-JAN, 4713 BC
pub type JulianDate = JulianDayNumber<JulianEpoch>;
pub const JULIAN_JD_OFFSET: f64 = 0.0_f64;
///
/// The Reduced Julian Date is the number of days since the [`REDUCED_JULIAN_EPOCH`]
/// or 2400000 days after the [`JULIAN_EPOCH`]
///
/// Noon 12:00 on 16-NOV-1858
pub type ReducedJulianDate = JulianDayNumber<ReducedJulianEpoch>;
/// The offset from the [`JULIAN_EPOCH`] for the [`ReducedJulianDate`]
pub const REDUCED_JD_OFFSET: f64 = 2400000_f64;
///
/// The Modified Julian Date shifts the Reduced Julian Date by 12 hours forward,
/// or 2400000.5 days after the [`JULIAN_EPOCH`]
///
/// Midnight on 17-NOV-1858
pub type ModifiedJulianDate = JulianDayNumber<ModifiedJulianEpoch>;
/// The offset from the [`JULIAN_EPOCH`] for the [`ModifiedJulianDate`]
pub const MODIFIED_JD_OFFSET: f64 = 2400000.5_f64;
///
/// The Truncated Julian Date uses the [`TRUNCATED_JULIAN_EPOCH`] as a round
/// offset of 2440000.5 after the [`JULIAN_EPOCH`]
///
/// Midnight on 24-MAY-1968
pub type TruncatedJulianDate = JulianDayNumber<TruncatedJulianEpoch>;
/// The offset from the [`JULIAN_EPOCH`] for the [`TruncatedJulianDate`]
pub const TRUNCATED_JD_OFFSET: f64 = 2440000.5_f64;
///
/// The Lilian Date is the day number offset from the [`GREGORIAN_EPOCH`],
/// 2299159.5 JD after the [`JULIAN_EPOCH`]
///
/// Midnight on 15-OCT-1582
pub type LilianDate = JulianDayNumber<LilianEpoch>;
/// The offset from the [`JULIAN_EPOCH`] for the [`LilianDate`]
pub const LILIAN_JD_OFFSET: f64 = 2299159.5_f64;
///
/// The Rata Die (Latin: "Fixed Date") is the fixed number of days in the Common
/// Era, since Midnight 01-01-0001 AD, 1721424.5 after [`JULIAN_EPOCH`]
pub type RataDieDate = JulianDayNumber<RataDieEpoch>;
/// The offset from the [`JULIAN_EPOCH`] for the [`RataDieDate`]
pub const RATA_DIE_JD_OFFSET: f64 = 1721424.5_f64;
/// The offset from the [`JULIAN_EPOCH`] for the [`UnixTimestamp`]
pub const UNIX_TS_JD_OFFSET: f64 = 2240587.5_f64;
macro_rules! impl_julian {
($date:ident,$epoch:ident,$offset:ident) => {
impl From<JulianDate> for $date {
fn from(value: JulianDate) -> Self {
$date::new($epoch, value.day_number - $offset)
}
}
impl From<$date> for JulianDate {
fn from(value: $date) -> Self {
JulianDate::new(JULIAN_EPOCH, value.day_number + $offset)
}
}
impl From<&JulianDate> for $date {
fn from(value: &JulianDate) -> Self {
$date::new($epoch, value.day_number - $offset)
}
}
impl From<&$date> for JulianDate {
fn from(value: &$date) -> Self {
JulianDate::new(JULIAN_EPOCH, value.day_number + $offset)
}
}
};
}
impl From<UnixTimestamp> for JulianDate {
fn from(value: UnixTimestamp) -> Self {
let jd = value.get_offset().as_seconds_f64() / SECONDS_IN_DAY as f64 + UNIX_TS_JD_OFFSET;
JulianDate::new(JULIAN_EPOCH, jd)
}
}
impl From<JulianDate> for UnixTimestamp {
fn from(value: JulianDate) -> Self {
let ts = (value.day_number - UNIX_TS_JD_OFFSET) * SECONDS_IN_DAY as f64;
UnixTimestamp::from_seconds_f64(ts)
}
}
impl_julian!(ReducedJulianDate, REDUCED_JULIAN_EPOCH, REDUCED_JD_OFFSET);
impl_julian!(ModifiedJulianDate, REDUCED_JULIAN_EPOCH, MODIFIED_JD_OFFSET);
impl_julian!(
TruncatedJulianDate,
TRUNCATED_JULIAN_EPOCH,
TRUNCATED_JD_OFFSET
);
impl_julian!(LilianDate, GREGORIAN_EPOCH, LILIAN_JD_OFFSET);
impl_julian!(RataDieDate, COMMON_ERA_EPOCH, RATA_DIE_JD_OFFSET);